<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8" />
    
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
  <title>
     虎虎生辉
  </title>
  
  <link rel="shortcut icon" href="/blog/favicon.ico" />
  
  
<link rel="stylesheet" href="/blog/css/style.css">

  
<script src="/blog/js/pace.min.js"></script>


  

  

<meta name="generator" content="Hexo 6.0.0"></head>

</html>

<body>
  <div id="app">
    <main class="content">
      
<section class="cover">
    
  <div class="cover-frame">
    <div class="bg-box">
      <img src="./images/tiger.jpg" alt="image frame" />
    </div>
    <div class="cover-inner text-center text-white">
      <h1><a href="/blog/">虎虎生辉</a></h1>
      <h2></h2>
      <div>
        
        <img
          src="./hu.png"
          class="cover-logo"
          alt="虎虎生辉"
        />
        
      </div>
    </div>
  </div>
  <div class="cover-learn-more">
    <a href="#main" class="anchor"><i class="ri-arrow-down-line"></i></a>
  </div>
</section>

<div id="main">
  <section class="outer">
  <article class="articles">
    
    <h1 class="page-type-title"></h1>

    
    
    <article id="post-CORSa" class="article article-type-post" itemscope
  itemprop="blogPost" data-scroll-reveal>

  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/blog/2019/05/01/CORSa/"
    >CORS原理详解</a
  >
</h2>
  

    </header>
    

    
    <div class="article-meta">
      <a href="/blog/2019/05/01/CORSa/" class="article-date">
  <time datetime="2019-05-01T08:25:57.000Z" itemprop="datePublished">2019-05-01</time>
</a>
      
    </div>
    

    

    <div class="article-entry" itemprop="articleBody">
      


      

      
      <blockquote>
<p>阅读本文，你需要首先知道：</p>
<ol>
<li>浏览器的同源策略</li>
<li>跨域问题</li>
<li>JSONP原理</li>
<li>cookie原理</li>
</ol>
</blockquote>
<p>JSONP并不是一个好的跨域解决方案，它至少有着下面两个严重问题：</p>
<ol>
<li><strong>会打乱服务器的消息格式</strong>：JSONP要求服务器响应一段JS代码，但在非跨域的情况下，服务器又需要响应一个正常的JSON格式</li>
<li><strong>只能完成GET请求</strong>：JSONP的原理会要求浏览器端生成一个<code>script</code>元素，而<code>script</code>元素发出的请求只能是<code>get</code>请求</li>
</ol>
<p>所以，CORS是一种更好的跨域解决方案。</p>
<h1 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h1><p><code>CORS</code>是基于<code>http1.1</code>的一种跨域解决方案，它的全称是<strong>C</strong>ross-<strong>O</strong>rigin <strong>R</strong>esource <strong>S</strong>haring，跨域资源共享。</p>
<p>它的总体思路是：<strong>如果浏览器要跨域访问服务器的资源，需要获得服务器的允许</strong></p>
<p><img src="http://mdrs.yuanjin.tech/img/image-20200421152122793.png" alt="image-20200421152122793"></p>
<p>而要知道，一个请求可以附带很多信息，从而会对服务器造成不同程度的影响</p>
<p>比如有的请求只是获取一些新闻，有的请求会改动服务器的数据</p>
<p>针对不同的请求，CORS规定了三种不同的交互模式，分别是：</p>
<ul>
<li><strong>简单请求</strong></li>
<li><strong>需要预检的请求</strong></li>
<li><strong>附带身份凭证的请求</strong></li>
</ul>
<p>这三种模式从上到下层层递进，请求可以做的事越来越多，要求也越来越严格。</p>
<p>下面分别说明三种请求模式的具体规范。</p>
<h1 id="简单请求"><a href="#简单请求" class="headerlink" title="简单请求"></a>简单请求</h1><p>当浏览器端运行了一段ajax代码（无论是使用XMLHttpRequest还是fetch api），浏览器会首先判断它属于哪一种请求模式</p>
<h2 id="简单请求的判定"><a href="#简单请求的判定" class="headerlink" title="简单请求的判定"></a>简单请求的判定</h2><p>当请求<strong>同时满足</strong>以下条件时，浏览器会认为它是一个简单请求：</p>
<ol>
<li><p><strong>请求方法属于下面的一种：</strong></p>
<ul>
<li>get</li>
<li>post</li>
<li>head</li>
</ul>
</li>
<li><p><strong>请求头仅包含安全的字段，常见的安全字段如下：</strong></p>
<ul>
<li><code>Accept</code></li>
<li><code>Accept-Language</code></li>
<li><code>Content-Language</code></li>
<li><code>Content-Type</code></li>
<li><code>DPR</code></li>
<li><code>Downlink</code></li>
<li><code>Save-Data</code></li>
<li><code>Viewport-Width</code></li>
<li><code>Width</code></li>
</ul>
</li>
<li><p><strong>请求头如果包含<code>Content-Type</code>，仅限下面的值之一：</strong></p>
<ul>
<li><code>text/plain</code></li>
<li><code>multipart/form-data</code></li>
<li><code>application/x-www-form-urlencoded</code></li>
</ul>
</li>
</ol>
<p>如果以上三个条件同时满足，浏览器判定为简单请求。</p>
<p>下面是一些例子：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 简单请求</span></span><br><span class="line">fetch(<span class="string">&quot;http://crossdomain.com/api/news&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 请求方法不满足要求，不是简单请求</span></span><br><span class="line">fetch(<span class="string">&quot;http://crossdomain.com/api/news&quot;</span>, &#123;</span><br><span class="line">  <span class="attr">method</span>:<span class="string">&quot;PUT&quot;</span></span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 加入了额外的请求头，不是简单请求</span></span><br><span class="line">fetch(<span class="string">&quot;http://crossdomain.com/api/news&quot;</span>, &#123;</span><br><span class="line">  <span class="attr">headers</span>:&#123;</span><br><span class="line">    <span class="attr">a</span>: <span class="number">1</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 简单请求</span></span><br><span class="line">fetch(<span class="string">&quot;http://crossdomain.com/api/news&quot;</span>, &#123;</span><br><span class="line">  <span class="attr">method</span>: <span class="string">&quot;post&quot;</span></span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">// content-type不满足要求，不是简单请求</span></span><br><span class="line">fetch(<span class="string">&quot;http://crossdomain.com/api/news&quot;</span>, &#123;</span><br><span class="line">  <span class="attr">method</span>: <span class="string">&quot;post&quot;</span>,</span><br><span class="line">  <span class="attr">headers</span>: &#123;</span><br><span class="line">    <span class="string">&quot;content-type&quot;</span>: <span class="string">&quot;application/json&quot;</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<h2 id="简单请求的交互规范"><a href="#简单请求的交互规范" class="headerlink" title="简单请求的交互规范"></a>简单请求的交互规范</h2><p>当浏览器判定某个<strong>ajax跨域请求</strong>是<strong>简单请求</strong>时，会发生以下的事情</p>
<ol>
<li><strong>请求头中会自动添加<code>Origin</code>字段</strong></li>
</ol>
<p>比如，在页面<code>http://my.com/index.html</code>中有以下代码造成了跨域</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 简单请求</span></span><br><span class="line">fetch(<span class="string">&quot;http://crossdomain.com/api/news&quot;</span>);</span><br></pre></td></tr></table></figure>

<p>请求发出后，请求头会是下面的格式：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">GET /api/news/ HTTP/1.1</span><br><span class="line">Host: crossdomain.com</span><br><span class="line">Connection: keep-alive</span><br><span class="line">...</span><br><span class="line">Referer: http://my.com/index.html</span><br><span class="line">Origin: http://my.com</span><br></pre></td></tr></table></figure>

<p>看到最后一行没，<code>Origin</code>字段会告诉服务器，是哪个源地址在跨域请求</p>
<ol start="2">
<li><strong>服务器响应头中应包含<code>Access-Control-Allow-Origin</code></strong></li>
</ol>
<p>当服务器收到请求后，如果允许该请求跨域访问，需要在响应头中添加<code>Access-Control-Allow-Origin</code>字段</p>
<p>该字段的值可以是：</p>
<ul>
<li>*：表示我很开放，什么人我都允许访问</li>
<li>具体的源：比如<code>http://my.com</code>，表示我就允许你访问</li>
</ul>
<blockquote>
<p>实际上，这两个值对于客户端<code>http://my.com</code>而言，都一样，因为客户端才不会管其他源服务器允不允许，就关心自己是否被允许</p>
<p>当然，服务器也可以维护一个可被允许的源列表，如果请求的<code>Origin</code>命中该列表，才响应<code>*</code>或具体的源</p>
<p><strong>为了避免后续的麻烦，强烈推荐响应具体的源</strong></p>
</blockquote>
<p>假设服务器做出了以下的响应：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">HTTP/1.1 200 OK</span><br><span class="line">Date: Tue, 21 Apr 2020 08:03:35 GMT</span><br><span class="line">...</span><br><span class="line">Access-Control-Allow-Origin: http://my.com</span><br><span class="line">...</span><br><span class="line"></span><br><span class="line">消息体中的数据</span><br></pre></td></tr></table></figure>

<p>当浏览器看到服务器允许自己访问后，高兴的像一个两百斤的孩子，于是，它就把响应顺利的交给js，以完成后续的操作</p>
<p>下图简述了整个交互过程</p>
<p><img src="http://mdrs.yuanjin.tech/img/image-20200421162846480.png" alt="image-20200421162846480"></p>
<h1 id="需要预检的请求"><a href="#需要预检的请求" class="headerlink" title="需要预检的请求"></a>需要预检的请求</h1><p>简单的请求对服务器的威胁不大，所以允许使用上述的简单交互即可完成。</p>
<p>但是，如果浏览器不认为这是一种简单请求，就会按照下面的流程进行：</p>
<ol>
<li><strong>浏览器发送预检请求，询问服务器是否允许</strong></li>
<li><strong>服务器允许</strong></li>
<li><strong>浏览器发送真实请求</strong></li>
<li><strong>服务器完成真实的响应</strong></li>
</ol>
<p>比如，在页面<code>http://my.com/index.html</code>中有以下代码造成了跨域</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 需要预检的请求</span></span><br><span class="line">fetch(<span class="string">&quot;http://crossdomain.com/api/user&quot;</span>, &#123;</span><br><span class="line">  <span class="attr">method</span>:<span class="string">&quot;POST&quot;</span>, <span class="comment">// post 请求</span></span><br><span class="line">  <span class="attr">headers</span>:&#123;  <span class="comment">// 设置请求头</span></span><br><span class="line">    <span class="attr">a</span>: <span class="number">1</span>,</span><br><span class="line">    <span class="attr">b</span>: <span class="number">2</span>,</span><br><span class="line">    <span class="string">&quot;content-type&quot;</span>: <span class="string">&quot;application/json&quot;</span></span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">body</span>: <span class="built_in">JSON</span>.stringify(&#123; <span class="attr">name</span>: <span class="string">&quot;袁小进&quot;</span>, <span class="attr">age</span>: <span class="number">18</span> &#125;) <span class="comment">// 设置请求体</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<p>浏览器发现它不是一个简单请求，则会按照下面的流程与服务器交互</p>
<ol>
<li><strong>浏览器发送预检请求，询问服务器是否允许</strong></li>
</ol>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">OPTIONS /api/user HTTP/1.1</span><br><span class="line">Host: crossdomain.com</span><br><span class="line">...</span><br><span class="line">Origin: http://my.com</span><br><span class="line">Access-Control-Request-Method: POST</span><br><span class="line">Access-Control-Request-Headers: a, b, content-type</span><br></pre></td></tr></table></figure>

<p>可以看出，这并非我们想要发出的真实请求，请求中不包含我们的响应头，也没有消息体。</p>
<p>这是一个预检请求，它的目的是询问服务器，是否允许后续的真实请求。</p>
<p>预检请求<strong>没有请求体</strong>，它包含了后续真实请求要做的事情</p>
<p>预检请求有以下特征：</p>
<ul>
<li>请求方法为<code>OPTIONS</code></li>
<li>没有请求体</li>
<li>请求头中包含<ul>
<li><code>Origin</code>：请求的源，和简单请求的含义一致</li>
<li><code>Access-Control-Request-Method</code>：后续的真实请求将使用的请求方法</li>
<li><code>Access-Control-Request-Headers</code>：后续的真实请求会改动的请求头</li>
</ul>
</li>
</ul>
<ol start="2">
<li><strong>服务器允许</strong></li>
</ol>
<p>服务器收到预检请求后，可以检查预检请求中包含的信息，如果允许这样的请求，需要响应下面的消息格式</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">HTTP/1.1 200 OK</span><br><span class="line">Date: Tue, 21 Apr 2020 08:03:35 GMT</span><br><span class="line">...</span><br><span class="line">Access-Control-Allow-Origin: http://my.com</span><br><span class="line">Access-Control-Allow-Methods: POST</span><br><span class="line">Access-Control-Allow-Headers: a, b, content-type</span><br><span class="line">Access-Control-Max-Age: 86400</span><br><span class="line">...</span><br></pre></td></tr></table></figure>

<p>对于预检请求，不需要响应任何的消息体，只需要在响应头中添加：</p>
<ul>
<li><code>Access-Control-Allow-Origin</code>：和简单请求一样，表示允许的源</li>
<li><code>Access-Control-Allow-Methods</code>：表示允许的后续真实的请求方法</li>
<li><code>Access-Control-Allow-Headers</code>：表示允许改动的请求头</li>
<li><code>Access-Control-Max-Age</code>：告诉浏览器，多少秒内，对于同样的请求源、方法、头，都不需要再发送预检请求了</li>
</ul>
<ol start="3">
<li><strong>浏览器发送真实请求</strong></li>
</ol>
<p>预检被服务器允许后，浏览器就会发送真实请求了，上面的代码会发生下面的请求数据</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">POST /api/user HTTP/1.1</span><br><span class="line">Host: crossdomain.com</span><br><span class="line">Connection: keep-alive</span><br><span class="line">...</span><br><span class="line">Referer: http://my.com/index.html</span><br><span class="line">Origin: http://my.com</span><br><span class="line"></span><br><span class="line">&#123;&quot;name&quot;: &quot;袁小进&quot;, &quot;age&quot;: 18 &#125;</span><br></pre></td></tr></table></figure>

<ol start="4">
<li><strong>服务器响应真实请求</strong></li>
</ol>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">HTTP/1.1 200 OK</span><br><span class="line">Date: Tue, 21 Apr 2020 08:03:35 GMT</span><br><span class="line">...</span><br><span class="line">Access-Control-Allow-Origin: http://my.com</span><br><span class="line">...</span><br><span class="line"></span><br><span class="line">添加用户成功</span><br></pre></td></tr></table></figure>



<p>可以看出，当完成预检之后，后续的处理与简单请求相同</p>
<p>下图简述了整个交互过程</p>
<p><img src="http://mdrs.yuanjin.tech/img/image-20200421165913320.png" alt="image-20200421165913320"></p>
<h1 id="附带身份凭证的请求"><a href="#附带身份凭证的请求" class="headerlink" title="附带身份凭证的请求"></a>附带身份凭证的请求</h1><p>默认情况下，ajax的跨域请求并不会附带cookie，这样一来，某些需要权限的操作就无法进行</p>
<p>不过可以通过简单的配置就可以实现附带cookie</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// xhr</span></span><br><span class="line"><span class="keyword">var</span> xhr = <span class="keyword">new</span> XMLHttpRequest();</span><br><span class="line">xhr.withCredentials = <span class="literal">true</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// fetch api</span></span><br><span class="line">fetch(url, &#123;</span><br><span class="line">  <span class="attr">credentials</span>: <span class="string">&quot;include&quot;</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<p>这样一来，该跨域的ajax请求就是一个<em>附带身份凭证的请求</em></p>
<p>当一个请求需要附带cookie时，无论它是简单请求，还是预检请求，都会在请求头中添加<code>cookie</code>字段</p>
<p>而服务器响应时，需要明确告知客户端：服务器允许这样的凭据</p>
<p>告知的方式也非常的简单，只需要在响应头中添加：<code>Access-Control-Allow-Credentials: true</code>即可</p>
<p>对于一个附带身份凭证的请求，若服务器没有明确告知，浏览器仍然视为跨域被拒绝。</p>
<p>另外要特别注意的是：**对于附带身份凭证的请求，服务器不得设置 <code>Access-Control-Allow-Origin 的值为*</code>*<em>。这就是为什么不推荐使用</em>的原因</p>
<h1 id="一个额外的补充"><a href="#一个额外的补充" class="headerlink" title="一个额外的补充"></a>一个额外的补充</h1><p>在跨域访问时，JS只能拿到一些最基本的响应头，如：Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma，如果要访问其他头，则需要服务器设置本响应头。</p>
<p><code>Access-Control-Expose-Headers</code>头让服务器把允许浏览器访问的头放入白名单，例如：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Access-Control-Expose-Headers: authorization, a, b</span><br></pre></td></tr></table></figure>

<p>这样JS就能够访问指定的响应头了。</p>

      
      <!-- 打赏 -->
      
    </div>
    <footer class="article-footer">
      <a data-url="https://gitee.com/huafu123/blog/2019/05/01/CORSa/" data-id="ckya9fc0p0001ygf64qcv2gd5"
        class="article-share-link">分享</a>
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/blog/tags/cors/" rel="tag">cors</a></li></ul>

    </footer>

  </div>

  

  
  
  

  

</article>
    
    <article id="post-Cookiea" class="article article-type-post" itemscope
  itemprop="blogPost" data-scroll-reveal>

  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/blog/2019/04/01/Cookiea/"
    >cookie的基本概念</a
  >
</h2>
  

    </header>
    

    
    <div class="article-meta">
      <a href="/blog/2019/04/01/Cookiea/" class="article-date">
  <time datetime="2019-04-01T08:24:27.000Z" itemprop="datePublished">2019-04-01</time>
</a>
      
    </div>
    

    

    <div class="article-entry" itemprop="articleBody">
      


      

      
      <h1 id="一个不大不小的问题"><a href="#一个不大不小的问题" class="headerlink" title="一个不大不小的问题"></a>一个不大不小的问题</h1><p>假设服务器有一个接口，通过请求这个接口，可以添加一个管理员</p>
<p>但是，不是任何人都有权力做这种操作的</p>
<p>那么服务器如何知道请求接口的人是有权力的呢？</p>
<p>答案是：只有登录过的管理员才能做这种操作</p>
<p>可问题是，客户端和服务器的传输使用的是http协议，http协议是无状态的，什么叫无状态，就是<strong>服务器不知道这一次请求的人，跟之前登录请求成功的人是不是同一个人</strong></p>
<p><img src="http://mdrs.yuanjin.tech/img/image-20200417161014030.png"></p>
<p><img src="http://mdrs.yuanjin.tech/img/image-20200417161244373.png"></p>
<p>由于http协议的无状态，服务器<strong>忘记</strong>了之前的所有请求，它无法确定这一次请求的客户端，就是之前登录成功的那个客户端。</p>
<blockquote>
<p>你可以把服务器想象成有着严重脸盲症的东哥，他没有办法分清楚跟他说话的人之前做过什么</p>
</blockquote>
<p>于是，服务器想了一个办法</p>
<p>它按照下面的流程来认证客户端的身份</p>
<ol>
<li>客户端登录成功后，服务器会给客户端一个出入证（令牌 token）</li>
<li>后续客户端的每次请求，都必须要附带这个出入证（令牌 token）</li>
</ol>
<p><img src="http://mdrs.yuanjin.tech/img/image-20200417161950450.png"></p>
<p>服务器发扬了认证不认人的优良传统，就可以很轻松的识别身份了。</p>
<p>但是，用户不可能只在一个网站登录，于是客户端会收到来自各个网站的出入证，因此，就要求客户端要有一个类似于卡包的东西，能够具备下面的功能：</p>
<ol>
<li><strong>能够存放多个出入证</strong>。这些出入证来自不同的网站，也可能是一个网站有多个出入证，分别用于出入不同的地方</li>
<li><strong>能够自动出示出入证</strong>。客户端在访问不同的网站时，能够自动的把对应的出入证附带请求发送出去。</li>
<li><strong>正确的出示出入证</strong>。客户端不能将肯德基的出入证发送给麦当劳。</li>
<li><strong>管理出入证的有效期</strong>。客户端要能够自动的发现那些已经过期的出入证，并把它从卡包内移除。</li>
</ol>
<p>能够满足上面所有要求的，就是cookie</p>
<p>cookie类似于一个卡包，专门用于存放各种出入证，并有着一套机制来自动管理这些证件。</p>
<p>卡包内的每一张卡片，称之为<strong>一个cookie</strong>。</p>
<h1 id="cookie的组成"><a href="#cookie的组成" class="headerlink" title="cookie的组成"></a>cookie的组成</h1><p>cookie是浏览器中特有的一个概念，它就像浏览器的专属卡包，管理着各个网站的身份信息。</p>
<p>每个cookie就相当于是属于某个网站的一个卡片，它记录了下面的信息：</p>
<ul>
<li>key：键，比如「身份编号」</li>
<li>value：值，比如袁小进的身份编号「14563D1550F2F76D69ECBF4DD54ABC95」，这有点像卡片的条形码，当然，它可以是任何信息</li>
<li>domain：域，表达这个cookie是属于哪个网站的，比如<code>yuanjin.tech</code>，表示这个cookie是属于<code>yuanjin.tech</code>这个网站的</li>
<li>path：路径，表达这个cookie是属于该网站的哪个基路径的，就好比是同一家公司不同部门会颁发不同的出入证。比如<code>/news</code>，表示这个cookie属于<code>/news</code>这个路径的。（后续详细解释）</li>
<li>secure：是否使用安全传输（后续详细解释）</li>
<li>expire：过期时间，表示该cookie在什么时候过期</li>
</ul>
<p>当浏览器向服务器发送一个请求的时候，它会瞄一眼自己的卡包，看看哪些卡片适合附带捎给服务器</p>
<p>如果一个cookie<strong>同时满足</strong>以下条件，则这个cookie会被附带到请求中</p>
<ul>
<li>cookie没有过期</li>
<li>cookie中的域和这次请求的域是匹配的<ul>
<li>比如cookie中的域是<code>yuanjin.tech</code>，则可以匹配的请求域是<code>yuanjin.tech</code>、<code>www.yuanjin.tech</code>、<code>blogs.yuanjin.tech</code>等等</li>
<li>比如cookie中的域是<code>www.yuanjin.tech</code>，则只能匹配<code>www.yuanjin.tech</code>这样的请求域</li>
<li>cookie是不在乎端口的，只要域匹配即可</li>
</ul>
</li>
<li>cookie中的path和这次请求的path是匹配的<ul>
<li>比如cookie中的path是<code>/news</code>，则可以匹配的请求路径可以是<code>/news</code>、<code>/news/detail</code>、<code>/news/a/b/c</code>等等，但不能匹配<code>/blogs</code></li>
<li>如果cookie的path是<code>/</code>，可以想象，能够匹配所有的路径</li>
</ul>
</li>
<li>验证cookie的安全传输<ul>
<li>如果cookie的secure属性是true，则请求协议必须是<code>https</code>，否则不会发送该cookie</li>
<li>如果cookie的secure属性是false，则请求协议可以是<code>http</code>，也可以是<code>https</code></li>
</ul>
</li>
</ul>
<p>如果一个cookie满足了上述的所有条件，则浏览器会把它自动加入到这次请求中</p>
<p>具体加入的方式是，<strong>浏览器会将符合条件的cookie，自动放置到请求头中</strong>，例如，当我在浏览器中访问百度的时候，它在请求头中附带了下面的cookie：</p>
<p><img src="http://mdrs.yuanjin.tech/img/image-20200417170328584.png"></p>
<p>看到打马赛克的地方了吗？这部分就是通过请求头<code>cookie</code>发送到服务器的，它的格式是<code>键=值; 键=值; 键=值; ...</code>，每一个键值对就是一个符合条件的cookie。</p>
<p><strong>cookie中包含了重要的身份信息，永远不要把你的cookie泄露给别人！！！</strong>否则，他人就拿到了你的证件，有了证件，就具备了为所欲为的可能性。</p>
<h1 id="如何设置cookie"><a href="#如何设置cookie" class="headerlink" title="如何设置cookie"></a>如何设置cookie</h1><p>由于cookie是保存在浏览器端的，同时，很多证件又是服务器颁发的</p>
<p>所以，cookie的设置有两种模式：</p>
<ul>
<li>服务器响应：这种模式是非常普遍的，当服务器决定给客户端颁发一个证件时，它会在响应的消息中包含cookie，浏览器会自动的把cookie保存到卡包中</li>
<li>客户端自行设置：这种模式少见一些，不过也有可能会发生，比如用户关闭了某个广告，并选择了「以后不要再弹出」，此时就可以把这种小信息直接通过浏览器的JS代码保存到cookie中。后续请求服务器时，服务器会看到客户端不想要再次弹出广告的cookie，于是就不会再发送广告过来了。</li>
</ul>
<h2 id="服务器端设置cookie"><a href="#服务器端设置cookie" class="headerlink" title="服务器端设置cookie"></a>服务器端设置cookie</h2><p>服务器可以通过设置响应头，来告诉浏览器应该如何设置cookie</p>
<p>响应头按照下面的格式设置：</p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">set-cookie:</span> <span class="string">cookie1</span></span><br><span class="line"><span class="attr">set-cookie:</span> <span class="string">cookie2</span></span><br><span class="line"><span class="attr">set-cookie:</span> <span class="string">cookie3</span></span><br><span class="line"><span class="string">...</span></span><br></pre></td></tr></table></figure>

<p>通过这种模式，就可以在一次响应中设置多个cookie了，具体设置多少个cookie，设置什么cookie，根据你的需要自行处理</p>
<p>其中，每个cookie的格式如下：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">键=值; path=?; domain=?; expire=?; max-age=?; secure; httponly</span><br></pre></td></tr></table></figure>

<p>每个cookie除了键值对是必须要设置的，其他的属性都是可选的，并且顺序不限</p>
<p>当这样的响应头到达客户端后，<strong>浏览器会自动的将cookie保存到卡包中，如果卡包中已经存在一模一样的卡片（其他key、path、domain相同），则会自动的覆盖之前的设置</strong>。</p>
<p>下面，依次说明每个属性值：</p>
<ul>
<li><strong>path</strong>：设置cookie的路径。如果不设置，浏览器会将其自动设置为当前请求的路径。比如，浏览器请求的地址是<code>/login</code>，服务器响应了一个<code>set-cookie: a=1</code>，浏览器会将该cookie的path设置为请求的路径<code>/login</code></li>
<li><strong>domain</strong>：设置cookie的域。如果不设置，浏览器会自动将其设置为当前的请求域，比如，浏览器请求的地址是<code>http://www.yuanjin.tech</code>，服务器响应了一个<code>set-cookie: a=1</code>，浏览器会将该cookie的domain设置为请求的域<code>www.yuanjin.tech</code><ul>
<li>这里值得注意的是，如果服务器响应了一个无效的域，浏览器是不认的</li>
<li>什么是无效的域？就是响应的域连根域都不一样。比如，浏览器请求的域是<code>yuanjin.tech</code>，服务器响应的cookie是<code>set-cookie: a=1; domain=baidu.com</code>，这样的域浏览器是不认的。</li>
<li>如果浏览器连这样的情况都允许，就意味着张三的服务器，有权利给用户一个cookie，用于访问李四的服务器，这会造成很多安全性的问题</li>
</ul>
</li>
<li><strong>expire</strong>：设置cookie的过期时间。这里必须是一个有效的GMT时间，即格林威治标准时间字符串，比如<code>Fri, 17 Apr 2020 09:35:59 GMT</code>，表示格林威治时间的<code>2020-04-17 09:35:59</code>，即北京时间的<code>2020-04-17 17:35:59</code>。当客户端的时间达到这个时间点后，会自动销毁该cookie。</li>
<li><strong>max-age</strong>：设置cookie的相对有效期。expire和max-age通常仅设置一个即可。比如设置<code>max-age</code>为<code>1000</code>，浏览器在添加cookie时，会自动设置它的<code>expire</code>为当前时间加上1000秒，作为过期时间。<ul>
<li>如果不设置expire，又没有设置max-age，则表示会话结束后过期。</li>
<li>对于大部分浏览器而言，关闭所有浏览器窗口意味着会话结束。</li>
</ul>
</li>
<li><strong>secure</strong>：设置cookie是否是安全连接。如果设置了该值，则表示该cookie后续只能随着<code>https</code>请求发送。如果不设置，则表示该cookie会随着所有请求发送。</li>
<li><strong>httponly</strong>：设置cookie是否仅能用于传输。如果设置了该值，表示该cookie仅能用于传输，而不允许在客户端通过JS获取，这对防止跨站脚本攻击（XSS）会很有用。 <ul>
<li>关于如何通过JS获取，后续会讲解</li>
<li>关于什么是XSS，不在本文讨论范围</li>
</ul>
</li>
</ul>
<p>下面来一个例子，客户端通过<code>post</code>请求服务器<code>http://yuanjin.tech/login</code>，并在消息体中给予了账号和密码，服务器验证登录成功后，在响应头中加入了以下内容：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">set-cookie: token=123456; path=/; max-age=3600; httponly</span><br></pre></td></tr></table></figure>

<p>当该响应到达浏览器后，浏览器会创建下面的cookie：</p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">key:</span> <span class="string">token</span></span><br><span class="line"><span class="attr">value:</span> <span class="number">123456</span></span><br><span class="line"><span class="attr">domain:</span> <span class="string">yuanjin.tech</span></span><br><span class="line"><span class="attr">path:</span> <span class="string">/</span></span><br><span class="line"><span class="attr">expire:</span> <span class="number">2020-04-17 18:55:00</span> <span class="comment">#假设当前时间是2020-04-17 17:55:00</span></span><br><span class="line"><span class="attr">secure:</span> <span class="literal">false</span>  <span class="comment">#任何请求都可以附带这个cookie，只要满足其他要求</span></span><br><span class="line"><span class="attr">httponly:</span> <span class="literal">true</span> <span class="comment">#不允许JS获取该cookie</span></span><br></pre></td></tr></table></figure>

<p>于是，随着浏览器后续对服务器的请求，只要满足要求，这个cookie就会被附带到请求头中传给服务器：</p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">cookie:</span> <span class="string">token=123456;</span> <span class="string">其他cookie...</span></span><br></pre></td></tr></table></figure>

<p>现在，还剩下最后一个问题，就是如何删除浏览器的一个cookie呢？</p>
<p>如果要删除浏览器的cookie，只需要让服务器响应一个同样的域、同样的路径、同样的key，只是时间过期的cookie即可</p>
<p><strong>所以，删除cookie其实就是修改cookie</strong></p>
<p>下面的响应会让浏览器删除<code>token</code></p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">cookie:</span> <span class="string">token=;</span> <span class="string">domain=yuanjin.tech;</span> <span class="string">path=/;</span> <span class="string">max-age=-1</span></span><br></pre></td></tr></table></figure>

<p>浏览器按照要求修改了cookie后，会发现cookie已经过期，于是自然就会删除了。</p>
<blockquote>
<p>无论是修改还是删除，都要注意cookie的域和路径，因为完全可能存在域或路径不同，但key相同的cookie</p>
<p>因此无法仅通过key确定是哪一个cookie</p>
</blockquote>
<h2 id="客户端设置cookie"><a href="#客户端设置cookie" class="headerlink" title="客户端设置cookie"></a>客户端设置cookie</h2><p>既然cookie是存放在浏览器端的，所以浏览器向JS公开了接口，让其可以设置cookie</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">document</span>.cookie = <span class="string">&quot;键=值; path=?; domain=?; expire=?; max-age=?; secure&quot;</span>;</span><br></pre></td></tr></table></figure>

<p>可以看出，在客户端设置cookie，和服务器设置cookie的格式一样，只是有下面的不同</p>
<ul>
<li>没有httponly。因为httponly本来就是为了限制在客户端访问的，既然你是在客户端配置，自然失去了限制的意义。</li>
<li>path的默认值。在服务器端设置cookie时，如果没有写path，使用的是请求的path。而在客户端设置cookie时，也许根本没有请求发生。因此，path在客户端设置时的默认值是当前网页的path</li>
<li>domain的默认值。和path同理，客户端设置时的默认值是当前网页的domain</li>
<li>其他：一样</li>
<li>删除cookie：和服务器也一样，修改cookie的过期时间即可</li>
</ul>
<h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>以上，就是cookie原理部分的内容。</p>
<p>如果把它用于登录场景，就是如下的流程：</p>
<p><strong>登录请求</strong></p>
<ol>
<li>浏览器发送请求到服务器，附带账号密码</li>
<li>服务器验证账号密码是否正确，如果不正确，响应错误，如果正确，在响应头中设置cookie，附带登录认证信息（至于登录认证信息是设么样的，如何设计，要考虑哪些问题，就是另一个话题了，可以百度 jwt）</li>
<li>客户端收到cookie，浏览器自动记录下来</li>
</ol>
<p><strong>后续请求</strong></p>
<ol>
<li>浏览器发送请求到服务器，希望添加一个管理员，并将cookie自动附带到请求中</li>
<li>服务器先获取cookie，验证cookie中的信息是否正确，如果不正确，不予以操作，如果正确，完成正常的业务流程</li>
</ol>

      
      <!-- 打赏 -->
      
    </div>
    <footer class="article-footer">
      <a data-url="https://gitee.com/huafu123/blog/2019/04/01/Cookiea/" data-id="ckya9fc0x0009ygf6d3a6c0gu"
        class="article-share-link">分享</a>
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/blog/tags/cookie/" rel="tag">cookie</a></li></ul>

    </footer>

  </div>

  

  
  
  

  

</article>
    
    <article id="post-JWTa" class="article article-type-post" itemscope
  itemprop="blogPost" data-scroll-reveal>

  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/blog/2019/03/01/JWTa/"
    >JWT原理详解</a
  >
</h2>
  

    </header>
    

    
    <div class="article-meta">
      <a href="/blog/2019/03/01/JWTa/" class="article-date">
  <time datetime="2019-03-01T08:28:11.000Z" itemprop="datePublished">2019-03-01</time>
</a>
      
    </div>
    

    

    <div class="article-entry" itemprop="articleBody">
      


      

      
      <p>随着前后端分离的发展，以及数据中心的建立，越来越多的公司会创建一个中心服务器，服务于各种产品线。</p>
<p>而这些产品线上的产品，它们可能有着各种终端设备，包括但不仅限于浏览器、桌面应用、移动端应用、平板应用、甚至智能家居</p>
<p><img src="http://mdrs.yuanjin.tech/img/image-20200422163727151.png" alt="image-20200422163727151"></p>
<blockquote>
<p>实际上，不同的产品线通常有自己的服务器，产品内部的数据一般和自己的服务器交互。</p>
<p>但中心服务器仍然有必要存在，因为同一家公司的产品总是会存在共享的数据，比如用户数据</p>
</blockquote>
<p>这些设备与中心服务器之间会进行http通信</p>
<p>一般来说，中心服务器至少承担着认证和授权的功能，例如登录：各种设备发送消息到中心服务器，然后中心服务器响应一个身份令牌（参见<a target="_blank" rel="noopener" href="http://www.yuanjin.tech/article/98">cookie原理详解</a>）</p>
<p>当这种结构出现后，就出现一个问题：它们之间还能使用传统的cookie方式传递令牌信息吗？</p>
<p>其实，也是可以的🐶，因为cookie在传输中无非是一个消息头而已，只不过浏览器对这个消息头有特殊处理罢了。</p>
<p>但浏览器之外的设备肯定不喜欢cookie，因为浏览器有着对cookie完善的管理机制，但是在其他设备上，就需要开发者自己手动处理了</p>
<p>jwt的出现就是为了解决这个问题</p>
<h1 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h1><p>jwt全称<code>Json Web Token</code>，强行翻译过来就是<code>json格式的互联网令牌</code>（算了，还是不要强行翻译了🐷）</p>
<p>它要解决的问题，就是为多种终端设备，提供<strong>统一的、安全的</strong>令牌格式</p>
<p><img src="http://mdrs.yuanjin.tech/img/image-20200422165350268.png" alt="image-20200422165350268"></p>
<p>因此，jwt只是一个令牌格式而已，你可以把它存储到cookie，也可以存储到localstorage，没有任何限制！</p>
<p>同样的，对于传输，你可以使用任何传输方式来传输jwt，一般来说，我们会使用消息头来传输它</p>
<p>比如，当登录成功后，服务器可以给客户端响应一个jwt：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">HTTP/1.1 200 OK</span><br><span class="line">...</span><br><span class="line">set-cookie:token=jwt令牌</span><br><span class="line">authorization:jwt令牌</span><br><span class="line">...</span><br><span class="line"></span><br><span class="line">&#123;..., token:jwt令牌&#125;</span><br></pre></td></tr></table></figure>

<p>可以看到，jwt令牌可以出现在响应的任何一个地方，客户端和服务器自行约定即可。</p>
<blockquote>
<p>当然，它也可以出现在响应的多个地方，比如为了充分利用浏览器的cookie，同时为了照顾其他设备，也可以让jwt出现在<code>set-cookie</code>和<code>authorization或body</code>中，尽管这会增加额外的传输量。</p>
</blockquote>
<p>当客户端拿到令牌后，它要做的只有一件事：存储它。</p>
<p>你可以存储到任何位置，比如手机文件、PC文件、localstorage、cookie</p>
<p>当后续请求发生时，你只需要将它作为请求的一部分发送到服务器即可。</p>
<p>虽然jwt没有明确要求应该如何附带到请求中，但通常我们会使用如下的格式：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">GET /api/resources HTTP/1.1</span><br><span class="line">...</span><br><span class="line">authorization: bearer jwt令牌</span><br><span class="line">...</span><br></pre></td></tr></table></figure>

<blockquote>
<p>这种格式是OAuth2附带token的一种规范格式</p>
<p>至于什么是OAuth2，那是另一个话题了</p>
</blockquote>
<p>这样一来，服务器就能够收到这个令牌了，通过对令牌的验证，即可知道该令牌是否有效。</p>
<p>它们的完整交互流程是非常简单清晰的</p>
<p><img src="http://mdrs.yuanjin.tech/img/image-20200422172837190.png" alt="image-20200422172837190"></p>
<h1 id="令牌的组成"><a href="#令牌的组成" class="headerlink" title="令牌的组成"></a>令牌的组成</h1><p>为了保证令牌的安全性，jwt令牌由三个部分组成，分别是：</p>
<ol>
<li>header：令牌头部，记录了整个令牌的类型和签名算法</li>
<li>payload：令牌负荷，记录了保存的主体信息，比如你要保存的用户信息就可以放到这里</li>
<li>signature：令牌签名，按照头部固定的签名算法对整个令牌进行签名，该签名的作用是：保证令牌不被伪造和篡改</li>
</ol>
<p>它们组合而成的完整格式是：<code>header.payload.signature</code></p>
<p>比如，一个完整的jwt令牌如下：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpYXQiOjE1ODc1NDgyMTV9.BCwUy3jnUQ_E6TqCayc7rCHkx-vxxdagUwPOWqwYCFc</span><br></pre></td></tr></table></figure>

<p>它各个部分的值分别是：</p>
<ul>
<li><code>header：eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9</code></li>
<li><code>payload：eyJmb28iOiJiYXIiLCJpYXQiOjE1ODc1NDgyMTV9</code></li>
<li><code>signature: BCwUy3jnUQ_E6TqCayc7rCHkx-vxxdagUwPOWqwYCFc</code></li>
</ul>
<p>下面分别对每个部分进行说明</p>
<h2 id="header"><a href="#header" class="headerlink" title="header"></a>header</h2><p>它是令牌头部，记录了整个令牌的类型和签名算法</p>
<p>它的格式是一个<code>json</code>对象，如下：</p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="attr">&quot;alg&quot;</span>:<span class="string">&quot;HS256&quot;</span>,</span><br><span class="line">  <span class="attr">&quot;typ&quot;</span>:<span class="string">&quot;JWT&quot;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>该对象记录了：</p>
<ul>
<li>alg：signature部分使用的签名算法，通常可以取两个值<ul>
<li>HS256：一种对称加密算法，使用同一个秘钥对signature加密解密</li>
<li>RS256：一种非对称加密算法，使用私钥加密，公钥解密</li>
</ul>
</li>
<li>typ：整个令牌的类型，固定写<code>JWT</code>即可</li>
</ul>
<p>设置好了<code>header</code>之后，就可以生成<code>header</code>部分了</p>
<p>具体的生成方式及其简单，就是把<code>header</code>部分使用<code>base64 url</code>编码即可</p>
<blockquote>
<p><code>base64 url</code>不是一个加密算法，而是一种编码方式，它是在<code>base64</code>算法的基础上对<code>+</code>、<code>=</code>、<code>/</code>三个字符做出特殊处理的算法</p>
<p>而<code>base64</code>是使用64个可打印字符来表示一个二进制数据，具体的做法参考<a target="_blank" rel="noopener" href="https://baike.baidu.com/item/base64/8545775?fr=aladdin">百度百科</a></p>
</blockquote>
<p>浏览器提供了<code>btoa</code>函数，可以完成这个操作：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">window</span>.btoa(<span class="built_in">JSON</span>.stringify(&#123;</span><br><span class="line">  <span class="string">&quot;alg&quot;</span>:<span class="string">&quot;HS256&quot;</span>,</span><br><span class="line">  <span class="string">&quot;typ&quot;</span>:<span class="string">&quot;JWT&quot;</span></span><br><span class="line">&#125;))</span><br><span class="line"><span class="comment">// 得到字符串：eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9</span></span><br></pre></td></tr></table></figure>

<p>同样的，浏览器也提供了<code>atob</code>函数，可以对其进行解码：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">window</span>.atob(<span class="string">&quot;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9&quot;</span>)</span><br><span class="line"><span class="comment">// 得到字符串：&#123;&quot;alg&quot;:&quot;HS256&quot;,&quot;typ&quot;:&quot;JWT&quot;&#125;</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>nodejs中没有提供这两个函数，可以安装第三方库<code>atob</code>和<code>bota</code>搞定</p>
<p>或者，手动搞定</p>
</blockquote>
<h2 id="payload"><a href="#payload" class="headerlink" title="payload"></a>payload</h2><p>这部分是jwt的主体信息，它仍然是一个JSON对象，它可以包含以下内容：</p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="attr">&quot;ss&quot;</span>：<span class="attr">&quot;发行者&quot;</span>,</span><br><span class="line">	<span class="attr">&quot;iat&quot;</span>：<span class="attr">&quot;发布时间&quot;</span>,</span><br><span class="line">	<span class="attr">&quot;exp&quot;</span>：<span class="attr">&quot;到期时间&quot;</span>,</span><br><span class="line">	<span class="attr">&quot;sub&quot;</span>：<span class="attr">&quot;主题&quot;</span>,</span><br><span class="line">	<span class="attr">&quot;aud&quot;</span>：<span class="attr">&quot;听众&quot;</span>,</span><br><span class="line">	<span class="attr">&quot;nbf&quot;</span>：<span class="attr">&quot;在此之前不可用&quot;</span>,</span><br><span class="line">  <span class="attr">&quot;jti&quot;</span>：<span class="attr">&quot;JWT ID&quot;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>以上属性可以全写，也可以一个都不写，它只是一个规范，就算写了，也需要你在将来验证这个jwt令牌时手动处理才能发挥作用</p>
<p>上述属性表达的含义分别是：</p>
<ul>
<li>ss：发行该jwt的是谁，可以写公司名字，也可以写服务名称</li>
<li>iat：该jwt的发放时间，通常写当前时间的时间戳</li>
<li>exp：该jwt的到期时间，通常写时间戳</li>
<li>sub：该jwt是用于干嘛的</li>
<li>aud：该jwt是发放给哪个终端的，可以是终端类型，也可以是用户名称，随意一点</li>
<li>nbf：一个时间点，在该时间点到达之前，这个令牌是不可用的</li>
<li>jti：jwt的唯一编号，设置此项的目的，主要是为了防止重放攻击（重放攻击是在某些场景下，用户使用之前的令牌发送到服务器，被服务器正确的识别，从而导致不可预期的行为发生）</li>
</ul>
<p>可是到现在，看了半天，没有出现我想要写入的数据啊😂</p>
<p>当用户登陆成功之后，我可能需要把用户的一些信息写入到jwt令牌中，比如用户id、账号等等（密码就算了😳）</p>
<p>其实很简单，payload这一部分只是一个json对象而已，你可以向对象中加入任何想要加入的信息</p>
<p>比如，下面的json对象仍然是一个有效的payload</p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="attr">&quot;foo&quot;</span>:<span class="string">&quot;bar&quot;</span>,</span><br><span class="line">  <span class="attr">&quot;iat&quot;</span>:<span class="number">1587548215</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><code>foo: bar</code>是我们自定义的信息，<code>iat: 1587548215</code>是jwt规范中的信息</p>
<p>最终，payload部分和header一样，需要通过<code>base64 url</code>编码得到：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">window</span>.btoa(<span class="built_in">JSON</span>.stringify(&#123;</span><br><span class="line">  <span class="string">&quot;foo&quot;</span>:<span class="string">&quot;bar&quot;</span>,</span><br><span class="line">  <span class="string">&quot;iat&quot;</span>:<span class="number">1587548215</span></span><br><span class="line">&#125;))</span><br><span class="line"><span class="comment">// 得到字符串：eyJmb28iOiJiYXIiLCJpYXQiOjE1ODc1NDgyMTV9</span></span><br></pre></td></tr></table></figure>

<h2 id="signature"><a href="#signature" class="headerlink" title="signature"></a>signature</h2><p>这一部分是jwt的签名，正是它的存在，保证了整个jwt不被篡改</p>
<p>这部分的生成，是对前面两个部分的编码结果，按照头部指定的方式进行加密</p>
<p>比如：头部指定的加密方法是<code>HS256</code>，前面两部分的编码结果是<code>eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpYXQiOjE1ODc1NDgyMTV9</code></p>
<p>则第三部分就是用对称加密算法<code>HS256</code>对字符串<code>eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpYXQiOjE1ODc1NDgyMTV9</code>进行加密，当然你得指定一个秘钥，比如<code>shhhhh</code></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">HS256(<span class="string">`eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpYXQiOjE1ODc1NDgyMTV9`</span>, <span class="string">&quot;shhhhh&quot;</span>)</span><br><span class="line"><span class="comment">// 得到：BCwUy3jnUQ_E6TqCayc7rCHkx-vxxdagUwPOWqwYCFc</span></span><br></pre></td></tr></table></figure>

<p>最终，将三部分组合在一起，就得到了完整的jwt</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpYXQiOjE1ODc1NDgyMTV9.BCwUy3jnUQ_E6TqCayc7rCHkx-vxxdagUwPOWqwYCFc</span><br></pre></td></tr></table></figure>

<p>由于签名使用的秘钥保存在服务器，这样一来，客户端就无法伪造出签名，因为它拿不到秘钥。</p>
<p>换句话说，之所以说无法伪造jwt，就是因为第三部分的存在。</p>
<p>而前面两部分并没有加密，只是一个编码结果而已，可以认为几乎是明文传输</p>
<blockquote>
<p>这不会造成太大的问题，因为既然用户登陆成功了，它当然有权力查看自己的用户信息</p>
<p>甚至在某些网站，用户的基本信息可以被任何人查看</p>
<p>你要保证的，是不要把敏感的信息存放到jwt中，比如密码</p>
</blockquote>
<p>jwt的<code>signature</code>可以保证令牌不被伪造，那如何保证令牌不被篡改呢？</p>
<p>比如，某个用户登陆成功了，获得了jwt，但他人为的篡改了<code>payload</code>，比如把自己的账户余额修改为原来的两倍，然后重新编码出<code>payload</code>发送到服务器，服务器如何得知这些信息被篡改过了呢？</p>
<p>这就要说到令牌的验证了</p>
<h1 id="令牌的验证"><a href="#令牌的验证" class="headerlink" title="令牌的验证"></a>令牌的验证</h1><p><img src="http://mdrs.yuanjin.tech/img/image-20200422172837190.png" alt="image-20200422172837190"></p>
<p>令牌在服务器组装完成后，会以任意的方式发送到客户端</p>
<p>客户端会把令牌保存起来，后续的请求会将令牌发送给服务器</p>
<p>而服务器需要验证令牌是否正确，如何验证呢？</p>
<p>首先，服务器要验证这个令牌是否被篡改过，验证方式非常简单，就是对<code>header+payload</code>用同样的秘钥和加密算法进行重新加密</p>
<p>然后把加密的结果和传入jwt的<code>signature</code>进行对比，如果完全相同，则表示前面两部分没有动过，就是自己颁发的，如果不同，肯定是被篡改过了。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">传入的header.传入的payload.传入的signature</span><br><span class="line">新的signature = header中的加密算法(传入的header.传入的payload, 秘钥)</span><br><span class="line">验证：新的signature == 传入的signature</span><br></pre></td></tr></table></figure>

<p>当令牌验证为没有被篡改后，服务器可以进行其他验证：比如是否过期、听众是否满足要求等等，这些就视情况而定了</p>
<p>注意：这些验证都需要服务器手动完成，没有哪个服务器会给你进行自动验证，当然，你可以借助第三方库来完成这些操作</p>
<h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>最后，总结一下jwt的特点：</p>
<ul>
<li>jwt本质上是一种令牌格式。它和终端设备无关，同样和服务器无关，甚至与如何传输无关，它只是规范了令牌的格式而已</li>
<li>jwt由三部分组成：header、payload、signature。主体信息在payload</li>
<li>jwt难以被篡改和伪造。这是因为有第三部分的签名存在。</li>
</ul>

      
      <!-- 打赏 -->
      
    </div>
    <footer class="article-footer">
      <a data-url="https://gitee.com/huafu123/blog/2019/03/01/JWTa/" data-id="ckya9fc12000hygf60lmr8s3p"
        class="article-share-link">分享</a>
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/blog/tags/jwt/" rel="tag">jwt</a></li></ul>

    </footer>

  </div>

  

  
  
  

  

</article>
    
    <article id="post-NODEJSa" class="article article-type-post" itemscope
  itemprop="blogPost" data-scroll-reveal>

  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/blog/2019/02/01/NODEJSa/"
    >NodeJs 初识</a
  >
</h2>
  

    </header>
    

    
    <div class="article-meta">
      <a href="/blog/2019/02/01/NODEJSa/" class="article-date">
  <time datetime="2019-02-01T08:31:26.000Z" itemprop="datePublished">2019-02-01</time>
</a>
      
    </div>
    

    

    <div class="article-entry" itemprop="articleBody">
      


      

      
      <h1 id="一、node-核心"><a href="#一、node-核心" class="headerlink" title="一、node 核心"></a>一、node 核心</h1><h2 id="（一）全局对象-global"><a href="#（一）全局对象-global" class="headerlink" title="（一）全局对象 global"></a>（一）全局对象 global</h2><h3 id="1-Buffer-缓冲器"><a href="#1-Buffer-缓冲器" class="headerlink" title="1.Buffer 缓冲器"></a>1.Buffer 缓冲器</h3><ul>
<li>Buffer 类是 JavaScript 的 Uint8Array 类的子类，且继承时带上了涵盖额外用例的方法。</li>
<li>当在 Buffer 和字符串之间转换时，可以指定字符编码。 如果未指定字符编码，则使用 UTF-8 作为默认值。</li>
<li>Buffer.from(data, encoding)</li>
<li>Buffer.byteLength(data, encoding)</li>
<li>Buffer.concat(list)</li>
<li>Buffer.isBuffer(obj)</li>
</ul>
<h3 id="2-process-进程"><a href="#2-process-进程" class="headerlink" title="2.process 进程"></a>2.process 进程</h3><ul>
<li>process 对象是一个全局变量，提供了有关当前 Node.js 进程的信息并对其进行控制。</li>
<li>process.arch：为其编译 Node.js 二进制文件的操作系统的 CPU 架构。</li>
<li>process.env： 属性会返回包含用户环境的对象</li>
<li>process.platform： 属性返回字符串，标识 Node.js 进程运行其上的操作系统平台。</li>
<li>process.cwd()： 方法会返回 Node.js 进程的当前工作目录。</li>
<li>process.ppid： 属性返回当前父进程的 PID。</li>
<li>process.pid： 属性返回进程的 PID。</li>
<li>process.kill(pid)：发送的信号可能是做一些与杀死目标进程无关的事情</li>
</ul>
<h3 id="3-console-控制台"><a href="#3-console-控制台" class="headerlink" title="3.console 控制台"></a>3.console 控制台</h3><ul>
<li>console 模块提供了一个简单的调试控制台，类似于 Web 浏览器提供的 JavaScript 控制台。</li>
<li>console.time([label]) 启动一个计时器，用以计算一个操作的持续时间。 计时器由一个唯一的 label 标识。</li>
<li>console.timeEnd([label]) 停止先前通过调用 console.time() 启动的计时器，并打印结果到 stdout。</li>
</ul>
<h3 id="4-commonJS-模块化"><a href="#4-commonJS-模块化" class="headerlink" title="4.commonJS 模块化"></a>4.commonJS 模块化</h3><ul>
<li>commonJS模块化是运行在一个函数下的<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> (<span class="params"><span class="built_in">exports</span>, <span class="built_in">require</span>, <span class="built_in">module</span>, __filename, __dirname</span>) </span>&#123;</span><br><span class="line">  <span class="comment">/*开发者代码片段*/</span></span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">module</span>.exports</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
</ul>
<h3 id="5-ES6-模块化"><a href="#5-ES6-模块化" class="headerlink" title="5.ES6 模块化"></a>5.ES6 模块化</h3><ul>
<li>ES6模块化是使用.mjs后缀，目前处于试验阶段</li>
</ul>
<hr>
<h2 id="（二）内置模块"><a href="#（二）内置模块" class="headerlink" title="（二）内置模块"></a>（二）内置模块</h2><h3 id="1-os-系统操作"><a href="#1-os-系统操作" class="headerlink" title="1.os 系统操作"></a>1.os 系统操作</h3><ul>
<li>os.EOL：操作系统特定的行末标志。<ul>
<li>在 POSIX 上是 \n。</li>
<li>在 Windows 上是 \r\n。</li>
</ul>
</li>
<li>os.arch()：返回为其编译 Node.js 二进制文件的操作系统的 CPU 架构。</li>
<li>os.cpus()：返回一个对象数组，其中包含有关每个逻辑 CPU 内核的信息。</li>
<li>os.freemem()：以整数的形式返回空闲的系统内存量（以字节为单位）。</li>
<li>os.homedir()：返回当前用户的主目录的字符串路径。</li>
<li>os.hostname()：以字符串的形式返回操作系统的主机名。</li>
<li>os.platform()： 返回标识操作系统平台的字符串。</li>
</ul>
<hr>
<h3 id="2-path-路径操作"><a href="#2-path-路径操作" class="headerlink" title="2.path 路径操作"></a>2.path 路径操作</h3><ul>
<li>path 模块提供了一些实用工具，用于处理文件和目录的路径。</li>
<li>path.dirname() 方法会返回 path 的目录名，类似于 Unix 的 dirname 命令。 尾部的目录分隔符会被忽略。</li>
<li>path.basename(path)：方法会返回 path 的最后一部分，类似于 Unix 的 basename 命令。 尾部的目录分隔符会被忽略。</li>
<li>path.extname()： 方法会返回 path 的扩展名，如果在 path 的最后一部分中没有，则返回空字符串。</li>
<li>path.format()： 方法从对象返回路径字符串。 </li>
<li>path.parse()： 方法从路径字符串返回对象。</li>
<li>path.isAbsolute()： 方法检测 path 是否为绝对路径。</li>
<li>path.relative(from, to)：方法根据当前工作目录返回 from 到 to 的相对路径。</li>
<li>path.resolve()： 方法会将路径或路径片段的序列解析为绝对路径。</li>
<li>path.join([…paths])：方法会将所有给定的 path 片段连接到一起（使用平台特定的分隔符作为定界符），然后规范化生成的路径。</li>
<li>path.normalize()： 方法规范化给定的 path，解析 ‘..’ 和 ‘.’ 片段。</li>
<li>path.delimiter：提供平台特定的路径定界符</li>
<li>path.sep：提供平台特定的路径片段分隔符</li>
</ul>
<hr>
<h3 id="3-url-地址操作"><a href="#3-url-地址操作" class="headerlink" title="3.url 地址操作"></a>3.url 地址操作</h3><ul>
<li>url 模块用于处理与解析 URL。</li>
<li>url.origin：获取只读的序列化的 URL 的 origin。<ul>
<li>url.protocol：获取及设置 URL 的协议部分。</li>
<li>url.host：获取及设置 URL 的主机部分。</li>
<li>url.hostname：获取及设置 URL 的主机名部分。 url.host 和 url.hostname 之间的区别是 url.hostname 不包含端口。</li>
<li>url.port：获取及设置 URL 的端口部分。</li>
</ul>
</li>
<li>url.pathname：获取及设置 URL 的路径部分。</li>
<li>url.search：获取及设置 URL 的序列化查询部分。</li>
<li>url.hash：获取及设置 URL 的片段部分。</li>
<li>url.href：获取 href 属性的值等同于调用 url.toString()。<ul>
<li>url.parse(urlString[, parseQueryString[, slashesDenoteHost]])</li>
<li>url.format(URL)</li>
<li>url.parse(urlString)</li>
</ul>
</li>
</ul>
<hr>
<h3 id="4-util-工具库"><a href="#4-util-工具库" class="headerlink" title="4.util 工具库"></a>4.util 工具库</h3><ul>
<li>util.callbackify(original) 将异步函数处理为回调模式</li>
<li>util.promisify(original) 将回调模式处理为异步函数</li>
<li>util.inherits(constructor, superConstructor) 请使用 ES6 extends 关键词获得语言层面的继承支持。</li>
</ul>
<hr>
<h3 id="5-fs-I-O操作"><a href="#5-fs-I-O操作" class="headerlink" title="5.fs I/O操作"></a>5.fs I/O操作</h3><ul>
<li>fs.Stats 对象提供了关于文件的信息。<ul>
<li>stats.isDirectory()</li>
<li>stats.isFile()</li>
<li>stats.size </li>
<li>stats.atime 表明上次访问此文件的时间戳。</li>
<li>stats.mtime 表明上次修改此文件的时间戳。</li>
<li>stats.ctime 表明上次更改文件状态的时间戳。</li>
<li>stats.birthtime 表示此文件的创建时间的时间戳。</li>
</ul>
</li>
<li>fs.readdir(path, option, callback) 读取文件目录</li>
<li>fs.readFile(path, option, callback) 读取文件</li>
<li>fs.readdir() 读取文件目录</li>
<li>fs.writeFile(path, data, option, callback) 写入文件</li>
<li>fs.mkdir(path[, options], callback) 创建目录</li>
<li>fs.rename(oldPath, newPath, callback) 重命名</li>
<li>fs.createReadStream(path[, options]) 此方法返回的可读流具有 64 kb 的默认 highWaterMark。<ul>
<li>配置：<ul>
<li>encoding： 编码方式</li>
<li>start： 起始字节</li>
<li>end: 结束字节</li>
<li>highWaterMark：流量大小</li>
</ul>
</li>
<li>事件：<ul>
<li>‘close’ 事件，当流或其底层资源（比如文件描述符）被关闭时触发。</li>
<li>‘data’ 事件，当流将数据块传送给消费者后触发。</li>
<li>‘end’ 事件，在数据被完全消费掉后才会触发。</li>
<li>‘error’ 事件，底层的流由于底层内部的故障而无法生成数据，或者流的实现尝试推送无效的数据块由 Readable 实现触发。</li>
<li>‘pause’ 事件，当调用 stream.pause() 并且 readsFlowing 不为 false 时触发。</li>
<li>‘resume’ 事件，当调用 stream.resume() 并且 readsFlowing 不为 true 时触发。</li>
<li>‘readable’ 事件，当有数据可从流中读取时触发。</li>
</ul>
</li>
<li>方法：<ul>
<li>readable.isPaused() 方法返回可读流当前的操作状态。</li>
<li>stream.pause() 读取暂停</li>
<li>stream.resume() 恢复读取</li>
</ul>
</li>
</ul>
</li>
<li>fs.createWriteStream(path[, options]) 此方法返回的可写流具有 64 kb 的默认 highWaterMark。<ul>
<li>事件：<ul>
<li>‘close’ 事件，当流或其底层资源（比如文件描述符）被关闭时触发。</li>
<li>‘data’ 事件，当流将数据块传送给消费者后触发。</li>
<li>‘end’ 事件，在数据被完全消费掉后才会触发。</li>
<li>‘error’ 事件，如果在写入或管道数据时发生错误，则会触发。</li>
<li>‘drain’ 事件，如果调用 stream.write(chunk) 返回 false，则当可以继续写入数据到流时会触发。</li>
<li>‘finish’ 事件，调用 stream.end() 且缓冲数据都已传给底层系统之后触发。</li>
</ul>
</li>
<li>方法：<ul>
<li>readable.write() 方法返回管道是否可继续流入。</li>
<li>stream.end() 结束写入</li>
</ul>
</li>
</ul>
</li>
</ul>
<hr>
<h3 id="6-net-网络"><a href="#6-net-网络" class="headerlink" title="6.net 网络"></a>6.net 网络</h3><ul>
<li>net.Server 类<ul>
<li>事件：<ul>
<li>‘close’ 事件，当 server 关闭的时候触发。</li>
<li>‘connection’ 事件，当一个新的连接建立的时候触发。</li>
<li>‘error’ 事件，当错误出现的时候触发。</li>
<li>‘listening’ 事件， 当调用 server.listen() 绑定服务器之后触发。</li>
</ul>
</li>
<li>方法：<ul>
<li>server.close([callback]) 阻止 server 接受新的连接并保持现有的连接。 </li>
<li>server.getConnections(callback) 异步获取服务器的当前并发连接数。</li>
<li>server.listen([port[, host[, backlog]]][, callback])  启动一个服务器来监听连接。</li>
</ul>
</li>
</ul>
</li>
<li>net.Socket 类<ul>
<li>事件：<ul>
<li>‘close’ 事件，一旦 socket 完全关闭就发出该事件。</li>
<li>‘connect’ 事件，当一个 socket 连接成功建立的时候触发。</li>
<li>‘error’ 事件，当错误出现的时候触发。</li>
<li>‘data’ 事件， 当接收到数据的时触发该事件。</li>
<li>‘drain’ 事件，当写入缓冲区变为空时触发。</li>
<li>‘end’ 事件，当 socket 的另一端发送一个 FIN 包的时候触发，从而结束 socket 的可读端。</li>
</ul>
</li>
<li>方法：<ul>
<li>server.close([callback]) 阻止 server 接受新的连接并保持现有的连接。 </li>
<li>server.getConnections(callback) 异步获取服务器的当前并发连接数。</li>
<li>socket.connect(port[, host][, connectListener]) 在给定的套接字上启动一个连接。</li>
<li>socket.end([data[, encoding]][, callback]) 半关闭 socket。</li>
<li>socket.pause() 暂停读写数据。也就是说，’data’ 事件将不会再被触发。可以用于上传节流。</li>
<li>socket.resume() 在调用 socket.pause() 之后恢复读取数据。</li>
<li>socket.write(data[, encoding][, callback]) 在 socket 上发送数据。</li>
</ul>
</li>
</ul>
</li>
<li>net.createConnection(port[, host][, connectListener])</li>
<li>net.createServer([options][, connectionListener])</li>
<li>net.connect(port[, host][, connectListener])</li>
</ul>
<hr>
<h3 id="7-http"><a href="#7-http" class="headerlink" title="7.http"></a>7.http</h3><ul>
<li>http.ClientRequest 类<ul>
<li>事件：<ul>
<li>‘abort’ 事件，当请求被客户端中止时触发。</li>
<li>‘connect’ 事件，每次服务器使用 CONNECT 方法响应请求时都会触发。</li>
<li>‘response’ 事件，当收到此请求的响应时触发。 此事件仅触发一次。</li>
</ul>
</li>
<li>方法：<ul>
<li>request.write(chunk[, encoding][, callback]) 发送一个请求主体的数据块。</li>
<li>request.end([data[, encoding]][, callback]) 完成发送请求。</li>
</ul>
</li>
</ul>
</li>
<li>http.Server 类<ul>
<li>事件：<ul>
<li>‘close’ 事件，当服务器关闭时触发。</li>
<li>‘connect’ 事件，每次客户端请求 HTTP CONNECT 方法时触发。</li>
<li>‘connection’ 事件，建立新的 TCP 流时会触发此事件。</li>
<li>‘request’ 事件，每当有请求时触发。 每个连接可能有多个请求（对于 HTTP Keep-Alive 连接而言）。</li>
</ul>
</li>
<li>方法：<ul>
<li>server.listen() 启动 HTTP 服务器用于监听连接。</li>
<li>server.close([callback]) 停止服务器接受新连接。</li>
</ul>
</li>
</ul>
</li>
<li>http.ServerResponse 类<ul>
<li>事件：<ul>
<li>‘close’ 事件，表明底层的连接已被终止。</li>
<li>‘finish’ 事件，响应发送后触发。</li>
</ul>
</li>
<li>方法：<ul>
<li>response.write(chunk[, encoding][, callback]) 发送一块响应主体。 可以多次调用该方法以提供连续的响应主体片段。</li>
<li>response.end([data[, encoding]][, callback]) 发送所有响应头和主体，该服务器应该视为此消息已完成。</li>
</ul>
</li>
</ul>
</li>
<li>http.IncomingMessage 类<ul>
<li>事件：<ul>
<li>‘aborted’ 事件，当请求中止时触发。</li>
<li>‘close’ 事件，表明底层连接已关闭。</li>
</ul>
</li>
<li>属性：<ul>
<li>message.url，仅对从 http.Server 获取的请求有效。请求的 URL 字符串。 它仅包含实际的 HTTP 请求中存在的 URL。</li>
<li>message.method，仅对从 http.Server 获取的请求有效。请求方法为字符串。 只读。</li>
<li>message.headers，请求或响应的消息头对象。</li>
</ul>
</li>
</ul>
</li>
<li><strong>http.request(url[, options][, callback]) 客户端</strong><ul>
<li>返回值：http.ClientRequest 对象</li>
<li>回调参数：http.IncomingMessage 对象</li>
</ul>
</li>
<li><strong>http.createServer([options][, requestListener]) 服务端</strong><ul>
<li>返回值：http.Server 对象</li>
<li>回调参数1：http.IncomingMessage 对象</li>
<li>回调参数2：http.ServerResponse 对象</li>
</ul>
</li>
</ul>
<hr>
<h3 id="8-events"><a href="#8-events" class="headerlink" title="8.events"></a>8.events</h3><ul>
<li>EventEmitter 类<ul>
<li>用于创建一个事件管理对象event</li>
<li>event.on() 注册事件</li>
<li>event.once() 注册事件</li>
<li>event.emit() 触发事件</li>
</ul>
</li>
</ul>
<hr>
<h2 id="（三）生命周期"><a href="#（三）生命周期" class="headerlink" title="（三）生命周期"></a>（三）生命周期</h2>
      
      <!-- 打赏 -->
      
    </div>
    <footer class="article-footer">
      <a data-url="https://gitee.com/huafu123/blog/2019/02/01/NODEJSa/" data-id="ckya9fc16000oygf63u049awn"
        class="article-share-link">分享</a>
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/blog/tags/nodeJs/" rel="tag">nodeJs</a></li></ul>

    </footer>

  </div>

  

  
  
  

  

</article>
    
    <article id="post-TYPESCRIPTa" class="article article-type-post" itemscope
  itemprop="blogPost" data-scroll-reveal>

  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/blog/2019/01/09/TYPESCRIPTa/"
    >typeScript 初识</a
  >
</h2>
  

    </header>
    

    
    <div class="article-meta">
      <a href="/blog/2019/01/09/TYPESCRIPTa/" class="article-date">
  <time datetime="2019-01-09T08:31:26.000Z" itemprop="datePublished">2019-01-09</time>
</a>
      
    </div>
    

    

    <div class="article-entry" itemprop="articleBody">
      


      

      
      <h1 id="一、入门"><a href="#一、入门" class="headerlink" title="一、入门"></a>一、入门</h1><h2 id="（一）环境配置"><a href="#（一）环境配置" class="headerlink" title="（一）环境配置"></a>（一）环境配置</h2><ol>
<li>安装 typescript<blockquote>
<p>yarn global add typescript</p>
</blockquote>
</li>
<li>配置 node 环境<blockquote>
<p>yarn add @types/node</p>
</blockquote>
</li>
<li>简化流程<blockquote>
<p>yarn add ts-node<br>yarn add nodemon</p>
</blockquote>
</li>
</ol>
<hr>
<h2 id="（二）基础"><a href="#（二）基础" class="headerlink" title="（二）基础"></a>（二）基础</h2><h3 id="1-基本类型"><a href="#1-基本类型" class="headerlink" title="1.基本类型"></a>1.基本类型</h3><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> str: <span class="built_in">string</span> = <span class="string">&#x27;&#x27;</span><span class="comment">//字符串</span></span><br><span class="line"><span class="keyword">const</span> num: <span class="built_in">number</span> = <span class="number">1</span><span class="comment">//数字</span></span><br><span class="line"><span class="keyword">const</span> bol: <span class="built_in">boolean</span> = <span class="literal">true</span><span class="comment">//布尔</span></span><br><span class="line"><span class="keyword">const</span> obj: <span class="built_in">object</span> = &#123;&#125;<span class="comment">//对象</span></span><br></pre></td></tr></table></figure>

<h3 id="2-数组约束"><a href="#2-数组约束" class="headerlink" title="2.数组约束"></a>2.数组约束</h3><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> arr1: <span class="built_in">any</span>[] = []<span class="comment">//数组，数组项可以是任意类型</span></span><br><span class="line"><span class="keyword">const</span> arr2: <span class="built_in">Array</span>&lt;<span class="built_in">any</span>&gt; = []<span class="comment">//数组，数组项可以是任意类型</span></span><br><span class="line"><span class="keyword">const</span> arr3: [] = [<span class="string">&#x27;&#x27;</span>, <span class="number">10</span>]<span class="comment">//数组，数组项可以是字符串或数字</span></span><br><span class="line"><span class="keyword">const</span> arr4: [<span class="built_in">string</span>, <span class="built_in">number</span>] = [<span class="string">&#x27;&#x27;</span>, <span class="number">10</span>]<span class="comment">//数组，数组项可以是字符串或数字</span></span><br><span class="line"><span class="keyword">const</span> arr5: (<span class="built_in">string</span>|<span class="built_in">number</span>)[] = [<span class="string">&#x27;&#x27;</span>, <span class="number">10</span>]<span class="comment">//数组，数组项可以是字符串或数字</span></span><br><span class="line"><span class="keyword">const</span> arr6: <span class="keyword">readonly</span> <span class="built_in">number</span>[] = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>]<span class="comment">//只读数组</span></span><br></pre></td></tr></table></figure>

<h3 id="3-函数约束"><a href="#3-函数约束" class="headerlink" title="3.函数约束"></a>3.函数约束</h3><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//无返回值</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">fn1</span>(<span class="params">a: <span class="built_in">number</span>, b: <span class="built_in">string</span></span>): <span class="title">void</span> </span>&#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">&#x27;hello&#x27;</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//永不结束</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">fn2</span>(<span class="params">a: <span class="built_in">number</span>, b: <span class="built_in">string</span></span>): <span class="title">never</span> </span>&#123;</span><br><span class="line">  <span class="keyword">while</span>(<span class="literal">true</span>)&#123;&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//函数重载</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">fn3</span>(<span class="params">a:<span class="built_in">number</span>, b:<span class="built_in">number</span></span>):<span class="title">number</span></span></span><br><span class="line"><span class="function"><span class="function"><span class="keyword">function</span> <span class="title">fn3</span>(<span class="params">a:<span class="built_in">string</span>, b:<span class="built_in">string</span></span>):<span class="title">string</span></span></span></span><br><span class="line"><span class="function"><span class="function"><span class="function"><span class="keyword">function</span> <span class="title">fn3</span>(<span class="params">a: <span class="built_in">number</span> | <span class="built_in">string</span>, b: <span class="built_in">number</span> | <span class="built_in">string</span></span>):<span class="title">number</span> | <span class="title">string</span> </span>&#123;</span></span></span><br><span class="line"><span class="function"><span class="function">  <span class="title">if</span> (<span class="params"><span class="keyword">typeof</span> a === <span class="string">&quot;number&quot;</span> &amp;&amp; <span class="keyword">typeof</span> b === <span class="string">&quot;number&quot;</span></span>) </span>&#123;</span></span><br><span class="line"><span class="function">    <span class="title">return</span> <span class="title">a</span> * <span class="title">b</span></span></span><br><span class="line"><span class="function">  &#125;</span></span><br><span class="line"><span class="function">  <span class="title">else</span> <span class="title">if</span> (<span class="params"><span class="keyword">typeof</span> a === <span class="string">&quot;string&quot;</span> &amp;&amp; <span class="keyword">typeof</span> a === <span class="string">&quot;string&quot;</span></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> a + b</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">&quot;a 和 b 类型必须相同！&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//                              可选参数     默认参数</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">fn</span>(<span class="params">a: <span class="built_in">number</span> | <span class="built_in">string</span>, b?: <span class="built_in">string</span>, c: <span class="built_in">string</span> = <span class="string">&quot;c&quot;</span></span>): <span class="title">void</span> </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (<span class="keyword">typeof</span> a === <span class="string">&quot;number&quot;</span>) &#123;</span><br><span class="line">    <span class="comment">//类型保护</span></span><br><span class="line">    <span class="built_in">console</span>.log(a)</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="built_in">console</span>.log(b, c)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="4-类型别名"><a href="#4-类型别名" class="headerlink" title="4.类型别名"></a>4.类型别名</h3><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//类型别名</span></span><br><span class="line"><span class="keyword">type</span> Type1 = <span class="string">&#x27;1&#x27;</span> | <span class="string">&#x27;2&#x27;</span></span><br><span class="line"><span class="keyword">type</span> Type2 = <span class="function">(<span class="params">a: <span class="built_in">string</span></span>) =&gt;</span> <span class="built_in">string</span></span><br><span class="line"><span class="keyword">type</span> Type3 = &#123;</span><br><span class="line">  (a: <span class="built_in">string</span>): <span class="built_in">string</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">type</span> Type4 = &#123;</span><br><span class="line">  T1?: <span class="string">&#x27;1&#x27;</span> | <span class="string">&#x27;2&#x27;</span><span class="comment">//成员可选</span></span><br><span class="line">  <span class="keyword">readonly</span> T2: <span class="keyword">readonly</span> <span class="built_in">number</span>[]<span class="comment">//只读成员</span></span><br><span class="line">  T3(a: <span class="built_in">number</span>): <span class="built_in">number</span></span><br><span class="line">  <span class="attr">T4</span>: <span class="function">(<span class="params">a: <span class="built_in">string</span></span>) =&gt;</span> <span class="built_in">string</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//组合</span></span><br><span class="line"><span class="keyword">type</span> A = &#123;</span><br><span class="line">  <span class="attr">a</span>: <span class="built_in">string</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">type</span> B = &#123;</span><br><span class="line">  <span class="attr">b</span>: <span class="built_in">number</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">type</span> C = &#123;</span><br><span class="line">  <span class="attr">c</span>: <span class="built_in">boolean</span></span><br><span class="line">&#125; &amp; A &amp; B</span><br></pre></td></tr></table></figure>

<h3 id="5-枚举"><a href="#5-枚举" class="headerlink" title="5.枚举"></a>5.枚举</h3><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">enum</span> Enum &#123;</span><br><span class="line">  prop1 = <span class="string">&quot;abc&quot;</span>,</span><br><span class="line">  prop2 = <span class="number">123</span>,</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> data: Enum;</span><br><span class="line">data = Enum.prop1 <span class="comment">// &quot;abc&quot;</span></span><br><span class="line">data = Enum.prop2 <span class="comment">// 123</span></span><br></pre></td></tr></table></figure>

<h3 id="6-接口"><a href="#6-接口" class="headerlink" title="6.接口"></a>6.接口</h3><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//接口</span></span><br><span class="line"><span class="keyword">interface</span> Type1 &#123;</span><br><span class="line">  (a: <span class="built_in">string</span>): <span class="built_in">string</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">interface</span> Type2 &#123;</span><br><span class="line">  T1?: <span class="string">&#x27;1&#x27;</span> | <span class="string">&#x27;2&#x27;</span><span class="comment">//成员可选</span></span><br><span class="line">  <span class="keyword">readonly</span> T2: <span class="keyword">readonly</span> <span class="built_in">number</span>[]<span class="comment">//只读成员</span></span><br><span class="line">  T3(a: <span class="built_in">number</span>): <span class="built_in">number</span></span><br><span class="line">  <span class="attr">T4</span>: <span class="function">(<span class="params">a: <span class="built_in">string</span></span>) =&gt;</span> <span class="built_in">string</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//继承</span></span><br><span class="line"><span class="keyword">interface</span> A &#123;</span><br><span class="line">  <span class="attr">a</span>: <span class="built_in">string</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">interface</span> B &#123;</span><br><span class="line">  <span class="attr">b</span>: <span class="built_in">number</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">interface</span> C <span class="keyword">extends</span> A, B&#123;</span><br><span class="line">  <span class="attr">c</span>: <span class="built_in">boolean</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="7-类"><a href="#7-类" class="headerlink" title="7.类"></a>7.类</h3><ul>
<li>属性列表描述</li>
<li>属性描述符</li>
<li>权限描述符</li>
<li>严格属性初始化</li>
<li>访问器属性<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">User</span></span>&#123;</span><br><span class="line">  <span class="comment">//属性列表描述</span></span><br><span class="line">  <span class="comment">//权限描述符</span></span><br><span class="line">  <span class="keyword">public</span> name: <span class="built_in">string</span></span><br><span class="line">  <span class="keyword">protected</span> sex: <span class="string">&quot;male&quot;</span> | <span class="string">&quot;female&quot;</span> = <span class="string">&quot;male&quot;</span></span><br><span class="line">  <span class="keyword">private</span> _age: <span class="built_in">number</span></span><br><span class="line">  <span class="comment">//属性描述符</span></span><br><span class="line">  <span class="comment">//语法糖，自动描述和赋值</span></span><br><span class="line">  <span class="function"><span class="title">constructor</span>(<span class="params"><span class="keyword">readonly</span> area: <span class="built_in">string</span>, like?:<span class="built_in">string</span></span>)</span> &#123;</span><br><span class="line">    </span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">//访问器属性</span></span><br><span class="line">  <span class="keyword">set</span> <span class="title">age</span>(<span class="params">newValue</span>) &#123;</span><br><span class="line">    <span class="built_in">this</span>._age = newValue</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">get</span> <span class="title">age</span>() &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">this</span>._age</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
</ul>
<h3 id="8-泛型"><a href="#8-泛型" class="headerlink" title="8.泛型"></a>8.泛型</h3><ul>
<li>函数泛型</li>
<li>类泛型</li>
<li>接口泛型</li>
<li>类型别名泛型</li>
<li>泛型约束（继承）</li>
<li>多泛型</li>
</ul>
<h3 id="9-类型兼容性"><a href="#9-类型兼容性" class="headerlink" title="9.类型兼容性"></a>9.类型兼容性</h3><ul>
<li>断言：<ul>
<li><type>data 断言</li>
<li>data as type 断言</li>
<li>data! 非空断言</li>
</ul>
</li>
<li>函数：<ul>
<li>参数：只能少，不能多</li>
<li>返回值：要求返回必须返回，不要求则随意</li>
</ul>
</li>
<li>对象：<ul>
<li>赋值：鸭子辨型法，成员只能多，不能少</li>
<li>字面量：严格完全匹配</li>
</ul>
</li>
</ul>
<hr>
<h2 id="（三）模块化"><a href="#（三）模块化" class="headerlink" title="（三）模块化"></a>（三）模块化</h2><h3 id="1-ES6-模块化标准"><a href="#1-ES6-模块化标准" class="headerlink" title="1.ES6 模块化标准"></a>1.ES6 模块化标准</h3><ul>
<li>export 声明</li>
<li>export default 默认导出</li>
<li>import 变量 from ‘path’</li>
</ul>
<h3 id="2-commonJS-模块化标准"><a href="#2-commonJS-模块化标准" class="headerlink" title="2.commonJS 模块化标准"></a>2.commonJS 模块化标准</h3><ul>
<li>exports.属性</li>
<li>module.export = {}</li>
<li>const 变量 require(‘path’)</li>
</ul>
<hr>
<h1 id="二、进阶"><a href="#二、进阶" class="headerlink" title="二、进阶"></a>二、进阶</h1><h2 id="（一）面向对象"><a href="#（一）面向对象" class="headerlink" title="（一）面向对象"></a>（一）面向对象</h2><h3 id="1-类的继承"><a href="#1-类的继承" class="headerlink" title="1.类的继承"></a>1.类的继承</h3><ul>
<li>A extends B<ul>
<li> A继承自B</li>
<li> A是子类、B是父类</li>
<li> 子类拥有父类的所有成员</li>
<li> 子类可以重写父类成员</li>
<li> this指向是动态的</li>
<li> super指向父类</li>
</ul>
</li>
<li>A instanceof B <ul>
<li>A是不是一个B</li>
<li>子类对象始终可以赋值给父类对象，当只能使用父类定义的成员，应使用类型保护</li>
<li>单根性：每个类只有一个父类（避免多继承）</li>
<li>传递性：隔代也是父子</li>
</ul>
</li>
<li>修饰符<ul>
<li>public 均可以访问</li>
<li>protected 自身及子类可以访问</li>
<li>private 自身可访问</li>
</ul>
</li>
</ul>
<h3 id="2-抽象类"><a href="#2-抽象类" class="headerlink" title="2.抽象类"></a>2.抽象类</h3><ul>
<li>abstract<ul>
<li>某个类只表示一个抽象的概念，只用于提取子类共有的成员，而不能直接创建对象</li>
<li>抽象成员，父类只知道类型，不知道具体的实现，且子类必须要将其实现</li>
</ul>
</li>
<li>模板模式<ul>
<li>所有子类实现某个方法流程一致，只有某一步骤不一致<ul>
<li>可能出现大量重复代码</li>
<li>重复代码提取后，可能出现调用顺序紊乱</li>
</ul>
</li>
<li>将该方法提取到父类实现</li>
<li>将不一致的地方提取到父类为抽象方法，让子类去具体实现</li>
<li>在父类方法中使用抽象方法</li>
</ul>
</li>
</ul>
<h3 id="3-静态成员"><a href="#3-静态成员" class="headerlink" title="3.静态成员"></a>3.静态成员</h3><ul>
<li>static<ul>
<li>某个成员属于类本身，而不是具体的对象</li>
<li>静态方法中this指向当前类</li>
</ul>
</li>
<li>单例模式<ul>
<li>某些类的实例对象，在系统中最多只能有一个（避免随意创建）</li>
<li>将构造函数私有 private</li>
<li>定义一个私有的静态属性，用于存储实例对象</li>
<li>定义一个公有的静态方法，用于得到实例对象<ul>
<li>判断静态属性是否已经有值，有值则直接返回该实例</li>
<li>没有则创建一个实例并赋值给静态属性，然后返回该实例</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="4-接口"><a href="#4-接口" class="headerlink" title="4.接口"></a>4.接口</h3><ul>
<li>implements<ul>
<li>表达某个类是否拥有某种能力（是否实现某个接口）</li>
</ul>
</li>
<li>类型保护函数<ul>
<li>参数：param</li>
<li>返回值：param is interface</li>
</ul>
</li>
<li>接口可继承类<ul>
<li>interface C extends A, B {}</li>
<li>用A、B类的所有成员实现一个类型</li>
</ul>
</li>
</ul>
<h3 id="5-索引器"><a href="#5-索引器" class="headerlink" title="5.索引器"></a>5.索引器</h3><ul>
<li>[prop: string]: any</li>
<li>[prop: number]: any<ul>
<li>索引器需书写于类的最顶端（所有成员之前）</li>
<li>可拓展对象</li>
<li>除了类定义的成员外，可通过索引器进行成员拓展</li>
<li>默认情况下，索引器可越过类型检查，需配置noImplicitAny</li>
<li>在js中所有的成员名，包括数组索引都是字符串类型，成员名在使用数字类型时，会进行隐式类型转换</li>
<li>在ts中成员名类型需要与索引器匹配</li>
</ul>
</li>
</ul>
<h3 id="6-this指向约束"><a href="#6-this指向约束" class="headerlink" title="6.this指向约束"></a>6.this指向约束</h3><ul>
<li>全局直接调用<ul>
<li>严格模式：this指向undefined</li>
<li>非严格模式：this指向全局对象</li>
</ul>
</li>
<li>对象方法调用<ul>
<li>this指向对象本身</li>
</ul>
</li>
<li>事件处理函数调用<ul>
<li>this指向事件处理对象</li>
</ul>
</li>
<li>箭头函数<ul>
<li>this指向声明位置的this指向</li>
</ul>
</li>
<li>bind、apply、call手动绑定this<ul>
<li>this指向绑定值</li>
</ul>
</li>
<li>在ts中默认与js一致，严格this指向约束，需配置noImplicitThis</li>
<li>在函数声明时，用第一个参数位置约定this指向</li>
</ul>
<h3 id="7-装饰器"><a href="#7-装饰器" class="headerlink" title="7.装饰器"></a>7.装饰器</h3><ul>
<li><strong>约束类</strong><ul>
<li>new () =&gt; object</li>
<li>()内约束构造函数参数</li>
</ul>
</li>
<li><strong>装饰类</strong><ul>
<li>本质是一个函数</li>
<li>参数：类本身</li>
<li>返回值：<ul>
<li>void：仅运行函数</li>
<li>class：替换原来的类</li>
</ul>
</li>
<li>运行时间<ul>
<li>定义类之后立即运行</li>
<li>多个装饰器，按栈的结构顺序运行（新进后出）</li>
</ul>
</li>
</ul>
</li>
<li><strong>装饰成员</strong><ul>
<li>本质是一个函数</li>
<li>参数：<ul>
<li>参数1：<ul>
<li>静态成员：类本身</li>
<li>实例成员：类原型</li>
</ul>
</li>
<li>参数2：成员名</li>
<li>参数3：Object.defineProperty</li>
</ul>
</li>
<li>返回值：<ul>
<li>void：仅运行函数</li>
<li>any：替换原来的成员</li>
</ul>
</li>
</ul>
</li>
<li><strong>reflect-metadata</strong><ul>
<li>第三方库</li>
<li>用于保存元数据</li>
</ul>
</li>
<li><strong>class-validator</strong><ul>
<li>第三方库</li>
<li>用于验证</li>
</ul>
</li>
<li><strong>class-transformer</strong><ul>
<li>第三方库</li>
<li>用于将平面对象转换为类对象</li>
</ul>
</li>
</ul>
<hr>
<h2 id="（二）类型演算"><a href="#（二）类型演算" class="headerlink" title="（二）类型演算"></a>（二）类型演算</h2><h3 id="1-关键字"><a href="#1-关键字" class="headerlink" title="1.关键字"></a>1.关键字</h3><ul>
<li>typeof</li>
<li>keyof</li>
<li>in</li>
</ul>
<h3 id="2-预设"><a href="#2-预设" class="headerlink" title="2.预设"></a>2.预设</h3><ul>
<li>Partial<T> 所有成员可选</li>
<li>Require<T> 所有成员必填</li>
<li>Readonly<T> 所有成员只读</li>
<li>Exclude&lt;T, U&gt; 剔除可以赋予给U的类型</li>
<li>Extract&lt;T, U&gt; 保留可以赋予给U的类型</li>
<li>NonNullable<T> 剔除null、undefined</li>
<li>ReturnType<typrof fn> 得到某个函数的返回类型 </li>
<li>InstanceType<typrof cl> 得到某个类的实例类型 </li>
</ul>
<hr>
<h2 id="（三）声明文件"><a href="#（三）声明文件" class="headerlink" title="（三）声明文件"></a>（三）声明文件</h2>
      
      <!-- 打赏 -->
      
    </div>
    <footer class="article-footer">
      <a data-url="https://gitee.com/huafu123/blog/2019/01/09/TYPESCRIPTa/" data-id="ckya9fc17000rygf6453yaar0"
        class="article-share-link">分享</a>
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/blog/tags/ts/" rel="tag">ts</a></li></ul>

    </footer>

  </div>

  

  
  
  

  

</article>
    
    <article id="post-REACTa" class="article article-type-post" itemscope
  itemprop="blogPost" data-scroll-reveal>

  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/blog/2018/10/01/REACTa/"
    >React 初识</a
  >
</h2>
  

    </header>
    

    
    <div class="article-meta">
      <a href="/blog/2018/10/01/REACTa/" class="article-date">
  <time datetime="2018-10-01T14:11:46.000Z" itemprop="datePublished">2018-10-01</time>
</a>
      
    </div>
    

    

    <div class="article-entry" itemprop="articleBody">
      


      

      
      <hr>
<h1 id="一、开发环境"><a href="#一、开发环境" class="headerlink" title="一、开发环境"></a>一、开发环境</h1><h2 id="（一）浏览器"><a href="#（一）浏览器" class="headerlink" title="（一）浏览器"></a>（一）浏览器</h2><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- react --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">crossorigin</span> <span class="attr">src</span>=<span class="string">&quot;https://unpkg.com/react@16/umd/react.development.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- react-dom --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">crossorigin</span> <span class="attr">src</span>=<span class="string">&quot;https://unpkg.com/react-dom@16/umd/react-dom.development.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- babel --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;https://unpkg.com/babel-standalone@6.15.0/babel.min.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">type</span>=<span class="string">&quot;text/babel&quot;</span>&gt;</span><span class="javascript"></span></span><br><span class="line"><span class="javascript"><span class="comment">// 使用jsx语法</span></span></span><br><span class="line"><span class="javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h2 id="（二）脚手架"><a href="#（二）脚手架" class="headerlink" title="（二）脚手架"></a>（二）脚手架</h2><ul>
<li><p>使用npm安装并使用</p>
<blockquote>
<p>cnpm install -g create-react-app<br>create-react-app my-app<br>cd my-app/<br>npm start</p>
</blockquote>
</li>
<li><p>使用yarn安装并使用</p>
<blockquote>
<p>yarn create react-app projectName</p>
</blockquote>
</li>
</ul>
<h2 id="（三）辅助功能"><a href="#（三）辅助功能" class="headerlink" title="（三）辅助功能"></a>（三）辅助功能</h2><ul>
<li>使用vscode编辑器<ul>
<li>配置emmet.includeLanguages支持jsx语法</li>
</ul>
</li>
<li>使用vscode插件<ul>
<li>ESLint代码风格实时检查</li>
<li>ES7 React/Redux/GraphQL/React-Native snippets代码模板快速生成</li>
</ul>
</li>
<li>使用Chrome浏览器<ul>
<li>React Developer Tools调试工具</li>
<li>Redux DevTools调试工具</li>
</ul>
</li>
</ul>
<hr>
<h1 id="二、React-核心"><a href="#二、React-核心" class="headerlink" title="二、React 核心"></a>二、React 核心</h1><p><a target="_blank" rel="noopener" href="https://zh-hans.reactjs.org/docs/react-api.html">React</a></p>
<p><a target="_blank" rel="noopener" href="https://zh-hans.reactjs.org/docs/react-dom.html">React Dom</a></p>
<h2 id="（一）JSX语法"><a href="#（一）JSX语法" class="headerlink" title="（一）JSX语法"></a>（一）JSX语法</h2><h3 id="1-书写规范"><a href="#1-书写规范" class="headerlink" title="1.书写规范"></a>1.书写规范</h3><ul>
<li>JSX语法本质是React.createElement()语法糖，在使用jsx语法的地方必须引用React模块</li>
<li>jsx表达式建议放在（）内</li>
<li>jsx表达式有且只有一个根节点，期望使用多个根节点时可使用React.Fragment元素包裹（使用语法糖&lt;&gt;&lt;/&gt;）</li>
<li>jsx表达式中每个元素必须结束（遵循XML规范）</li>
</ul>
<h3 id="2-嵌入js表达式"><a href="#2-嵌入js表达式" class="headerlink" title="2.嵌入js表达式"></a>2.嵌入js表达式</h3><h4 id="（1）插入元素内容"><a href="#（1）插入元素内容" class="headerlink" title="（1）插入元素内容"></a>（1）插入元素内容</h4><ul>
<li>使用{}进行表达式插入，{}内支持js表达式<ul>
<li>支持React元素对象，不支持普通对象，普通对象不能作为子元素</li>
<li>支持数组，进行遍历数组，数组项会被作为子元素，如果数组项是元素需要绑定key属性，key属性不会反应到真实DOM</li>
</ul>
</li>
<li>{}内结果如果是null、undefined、false不会作为子元素</li>
<li>jsx注释{/*…*/}</li>
</ul>
<h4 id="（2）插入元素属性"><a href="#（2）插入元素属性" class="headerlink" title="（2）插入元素属性"></a>（2）插入元素属性</h4><ul>
<li>属性使用小驼峰命名</li>
<li>元素属性值可以使用{}插入js表达式</li>
<li>className属性并不支持一个数组</li>
<li>style属性支持一个普通对象，对应css样式</li>
<li>dangerouslySetInnerHTML属性需要一个对象，对象带有一个__html属性，属性值使用innerHtml设置<ul>
<li>jsx默认使用innerText设置内容</li>
<li>自动编码，防止注入攻击</li>
</ul>
</li>
</ul>
<h3 id="3-元素不可变"><a href="#3-元素不可变" class="headerlink" title="3.元素不可变"></a>3.元素不可变</h3><ul>
<li>本质是Object.freeze()冻结了对象</li>
<li>子元素及属性均只可读，不可写</li>
</ul>
<hr>
<h2 id="（二）组件"><a href="#（二）组件" class="headerlink" title="（二）组件"></a>（二）组件</h2><h3 id="1-内置组件"><a href="#1-内置组件" class="headerlink" title="1.内置组件"></a>1.内置组件</h3><ul>
<li>html元素</li>
<li>React.Fragment组件</li>
<li>React.createContext().Provider组件</li>
<li>React.createContext().Consumer组件</li>
<li>React.StrictMode组件（严格模式）<ul>
<li>不会参与UI渲染</li>
<li>识别不安全的生命周期</li>
<li>检测意外的副作用</li>
<li>检测过时API</li>
</ul>
</li>
</ul>
<hr>
<h3 id="2-函数组件"><a href="#2-函数组件" class="headerlink" title="2.函数组件"></a>2.函数组件</h3><h4 id="（1）参数"><a href="#（1）参数" class="headerlink" title="（1）参数"></a>（1）参数</h4><ul>
<li>组件属性对象props</li>
</ul>
<h4 id="（2）返回值"><a href="#（2）返回值" class="headerlink" title="（2）返回值"></a>（2）返回值</h4><ul>
<li>React元素</li>
</ul>
<h4 id="（3）HOOK"><a href="#（3）HOOK" class="headerlink" title="（3）HOOK"></a>（3）HOOK</h4><ul>
<li>React &gt;= 16.8.0版本新增</li>
</ul>
<hr>
<h3 id="3-类组件"><a href="#3-类组件" class="headerlink" title="3.类组件"></a>3.类组件</h3><h4 id="（1）继承"><a href="#（1）继承" class="headerlink" title="（1）继承"></a>（1）继承</h4><ul>
<li>React.Component</li>
</ul>
<h4 id="（2）render-方法"><a href="#（2）render-方法" class="headerlink" title="（2）render()方法"></a>（2）render()方法</h4><ul>
<li>返回React元素</li>
</ul>
<h4 id="（3）属性"><a href="#（3）属性" class="headerlink" title="（3）属性"></a>（3）属性</h4><ul>
<li>constructor(props)构造函数方法拿到属性对象</li>
<li>super(props)将属性对象传递给父类</li>
<li>组件内通过this.props即可使用属性对象</li>
</ul>
<h4 id="（4）状态"><a href="#（4）状态" class="headerlink" title="（4）状态"></a>（4）状态</h4><ul>
<li>组件自己维护的数据，本质是类组件的一个属性（一个对象）</li>
<li>状态初始化：<ul>
<li>constructor构造函数内初始化</li>
<li>class字段初始化</li>
</ul>
</li>
<li>状态的改变：<ul>
<li>状态不能直接改变，必须使用this.setState()</li>
<li>状态的改变可能是异步的，若处于html事件中，则是异步的，否则是同步的<ul>
<li>this.setState(obj)，接受一个对象，与this.state进行混合并重新渲染（Object.assign(this.state, obj)）</li>
<li>this.setState(func)，接受一个函数，该函数有一个参数prev代表上一次的状态对象，返回一个对象与之前的状态进行混合（该函数会异步执行）</li>
<li>this.setState(obj | func, callback)接受第二个参数是一个回调函数，该回调在所有状态改变完成，重新渲染之后运行，在回调中获取的是最新状态</li>
</ul>
</li>
<li>React会对异步的this.setState()进行优化，将多次状态进行合并，所有状态改变完成后统一对this.state进行改变，然后进行重新渲染</li>
</ul>
</li>
</ul>
<h4 id="（5）声生命周期"><a href="#（5）声生命周期" class="headerlink" title="（5）声生命周期"></a>（5）声生命周期</h4><ul>
<li><p><strong>React &lt; 16.0.0版本</strong></p>
</li>
<li><p>constrouctor()</p>
<ul>
<li>组件初始化</li>
<li>同一个组件对象只会创建一次</li>
<li>禁止使用setState()</li>
</ul>
</li>
<li><p>render()</p>
<ul>
<li>构建虚拟DOM树并渲染真实DOM节点</li>
<li>禁止使用setState()</li>
</ul>
</li>
<li><p>componentDidMount()</p>
<ul>
<li>组件挂在完成</li>
<li>可以使用setState()</li>
<li>常用于副作用处理（网络请求、启动计时器）</li>
</ul>
</li>
<li><p>shouldComponentUpdate()</p>
<ul>
<li>参数1：新属性</li>
<li>参数2：新状态</li>
<li>返回值：boolean，是否重新渲染</li>
<li>用于性能优化</li>
</ul>
</li>
<li><p>componentWillUnMount()</p>
<ul>
<li>组件卸载</li>
<li>用于销毁组件依赖资源（取消计时器）<img src='./old.png' /></li>
</ul>
</li>
<li><p><strong>React &gt;= 16.0.0版本</strong></p>
</li>
<li><p>取消一些钩子函数：</p>
<ul>
<li>componentWillMount() 可能会有BUG</li>
<li>componentWillReceiveProps() 反模式问题</li>
<li>componentWillUpdate() 没有实际意义</li>
</ul>
</li>
<li><p>增加一些钩子函数：</p>
<ul>
<li>static getDerivedStateFromProps()<ul>
<li>静态函数，无法使用setState()</li>
<li>运行在初始化、属性变化、状态变化之后</li>
<li>参数1：新属性</li>
<li>参数2：新状态</li>
<li>返回值：Object，与状态进行混合</li>
</ul>
</li>
<li>getSnapshotBeforeUpdate()<ul>
<li>运行在DOM树构建完毕，页面即将渲染之前</li>
<li>参数1：旧属性</li>
<li>参数2：旧状态</li>
<li>返回值：componentDidUpdate()的第三个参数<img src='./new.png' /></li>
</ul>
</li>
</ul>
</li>
</ul>
<hr>
<h3 id="4-表单"><a href="#4-表单" class="headerlink" title="4. 表单"></a>4. 表单</h3><ul>
<li>默认情况下表单是非受控组件<ul>
<li>可以使用 defaultValue、 defaultChecked属性指定默认值</li>
<li>使用ref来操作真实DOM间接获得组件内容</li>
</ul>
</li>
<li>通过指定内容和事件使得表单成为受控组件<ul>
<li>使用value指定组件内容（来源于状态）</li>
<li>使用onChange()事件改编组件内容（改编状态）</li>
</ul>
</li>
</ul>
<hr>
<h3 id="5-HOC高阶组件"><a href="#5-HOC高阶组件" class="headerlink" title="5.HOC高阶组件"></a>5.HOC高阶组件</h3><ul>
<li>高阶组件是函数组件（通常以with前缀命名）<ul>
<li>参数：接受一个组件</li>
<li>返回值：返回一个组件</li>
</ul>
</li>
<li>利用高阶组件实现横切关注点<ul>
<li>抽离共同的功能</li>
<li>添加额外功能</li>
</ul>
</li>
<li>注意：<ul>
<li>不要在render()中使用高阶组件，会导致组件对象被重复销毁和创建</li>
<li>不要在高阶组件内修改传入的组件</li>
</ul>
</li>
</ul>
<hr>
<h3 id="6-纯组件"><a href="#6-纯组件" class="headerlink" title="6.纯组件"></a>6.纯组件</h3><h4 id="（1）PureComponent类组件"><a href="#（1）PureComponent类组件" class="headerlink" title="（1）PureComponent类组件"></a>（1）PureComponent类组件</h4><ul>
<li>作用于类组件</li>
<li>一个组件，如果某个组件继承自它，该组件会被优化</li>
<li>状态和属性会进行浅比较，如果没有变化，则不会重新渲染</li>
<li>本质就是优化了shouldComponentUpdate()</li>
</ul>
<h4 id="（2）React-memo-高阶组件"><a href="#（2）React-memo-高阶组件" class="headerlink" title="（2）React.memo()高阶组件"></a>（2）React.memo()高阶组件</h4><ul>
<li>作用于函数组件</li>
<li>本质就是给函数组件包裹了一层类组件，类组件继承PureComponent</li>
</ul>
<hr>
<h3 id="7-Portals插槽"><a href="#7-Portals插槽" class="headerlink" title="7.Portals插槽"></a>7.Portals插槽</h3><ul>
<li>不改变虚拟DOM树结构的情况下，将React元素渲染到指定的真实DOM容器中</li>
<li>使用ReactDOM.createPortals(React元素，真实DOM)<ul>
<li>参数1：需要渲染的React元素</li>
<li>参数2：真实DOM容器</li>
<li>返回值：一个ReactPortals组件</li>
</ul>
</li>
<li>注意事件冒泡<ul>
<li>React中的事件是被包装过的</li>
<li>React中的事件冒泡是根据虚拟DOM树结构冒泡的，与真实DOM层次结构无关</li>
</ul>
</li>
</ul>
<hr>
<h2 id="（三）属性"><a href="#（三）属性" class="headerlink" title="（三）属性"></a>（三）属性</h2><h3 id="1-数据传递"><a href="#1-数据传递" class="headerlink" title="1.数据传递"></a>1.数据传递</h3><ul>
<li>组件内部数据来源于状态state</li>
<li>组件内部数据来源于属性props</li>
<li>组件内部数据来源于上下文Context</li>
<li>组件使用者通过属性向组件内部传递数据<ul>
<li>传递普通数据</li>
<li>传递自定义事件处理程序</li>
<li>传递子元素（props.children）语法糖可以直接向html一样书写子元素</li>
</ul>
</li>
<li>组件内通过自定义事件参数向外部使用者传递数据</li>
</ul>
<h3 id="2-事件"><a href="#2-事件" class="headerlink" title="2.事件"></a>2.事件</h3><h4 id="（1）定义"><a href="#（1）定义" class="headerlink" title="（1）定义"></a>（1）定义</h4><ul>
<li>React事件本质就是一个属性，属性值是一个函数，遵循小驼峰命名</li>
<li>内置组件的事件与html事件保持一致</li>
<li>自定义组件的事件就是一个属性，在组件内部合适的时候调用该方法</li>
<li>在事件处理程序中，如果没有特殊处理，this指向undefined<ul>
<li>使用bind绑定this</li>
<li>使用箭头函数（字段初始化）</li>
</ul>
</li>
</ul>
<h4 id="（2）React事件"><a href="#（2）React事件" class="headerlink" title="（2）React事件"></a>（2）React事件</h4><ul>
<li>研究对象：内置html组件的事件</li>
<li>事件委托：本质只给document注册事件，几乎所有元素的事件处理，均在document事件中进行<ul>
<li>对于不会冒泡的事件或某些元素独有的事件则是在DOM元素自身上进行监听的</li>
<li>当在document中监听到某个事件的时候，查看虚拟DOM树中哪些元素注册了此事件，按照虚拟DOM树冒泡的顺序依次执行</li>
<li>当给真实DOM和虚拟DOM注册事件的时候，无论DOM层次结构如何，真实DOM永远先运行，因为虚拟DOM事件要等冒泡到document时才会运行</li>
<li>如果给真实DOM注册事件并阻止了冒泡，会导致虚拟DOM中的事件无法运行</li>
<li>如果给虚拟DOM注册事件并阻止了冒泡，本质上阻止的是document的冒泡并标记该虚拟DOM，在循环运行事件的时候会忽略被标记的事件<ul>
<li>所以阻止不了真实DOM事件</li>
<li>阻止的是虚拟DOM树的冒泡</li>
</ul>
</li>
</ul>
</li>
<li>事件对象：React中的事件对象是合成事件对象<ul>
<li>如果要是用真实事件对象，通过e.nativeEvent获得</li>
<li>如果是用e.nativeEvent中的方法，已经发生在冒泡到document事件中，可能不会符合预期</li>
<li>React中事件对象会被重用<ul>
<li>在事件处理程序中不要异步使用事件对象，事件处理程序结束时该对象会被重置，准备给下一个事件处理程序使用</li>
<li>通过e.persist()方法对事件对象持久化</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="3-属性默认值"><a href="#3-属性默认值" class="headerlink" title="3.属性默认值"></a>3.属性默认值</h3><ul>
<li>通过静态属性 defaultProps指定属性默认值</li>
<li>函数组件：funcName.defaultProps = {}</li>
<li>类组件：static defaultProps = {}</li>
</ul>
<h3 id="4-属性类型检查"><a href="#4-属性类型检查" class="headerlink" title="4.属性类型检查"></a>4.属性类型检查</h3><ul>
<li>使用prop-types库和静态属性propTypes 定义检查规则<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">PropTypes.any：<span class="comment">//任意类型</span></span><br><span class="line">PropTypes.array：<span class="comment">//数组类型</span></span><br><span class="line">PropTypes.bool：<span class="comment">//布尔类型</span></span><br><span class="line">PropTypes.func：<span class="comment">//函数类型</span></span><br><span class="line">PropTypes.number：<span class="comment">//数字类型</span></span><br><span class="line">PropTypes.object：<span class="comment">//对象类型</span></span><br><span class="line">PropTypes.string：<span class="comment">//字符串类型</span></span><br><span class="line">PropTypes.symbol：<span class="comment">//符号类型</span></span><br><span class="line"></span><br><span class="line">PropTypes.node：<span class="comment">//任何可以被渲染的内容，字符串、数字、React元素</span></span><br><span class="line">PropTypes.element：<span class="comment">//react元素</span></span><br><span class="line">PropTypes.elementType：<span class="comment">//react元素类型</span></span><br><span class="line">PropTypes.instanceOf(构造函数)：<span class="comment">//必须是指定构造函数的实例</span></span><br><span class="line">PropTypes.oneOf([xxx, xxx])：<span class="comment">//枚举</span></span><br><span class="line">PropTypes.oneOfType([xxx, xxx]);  <span class="comment">//属性类型必须是数组中的其中一个</span></span><br><span class="line">PropTypes.arrayOf(PropTypes.XXX)：<span class="comment">//必须是某一类型组成的数组</span></span><br><span class="line">PropTypes.objectOf(PropTypes.XXX)：<span class="comment">//对象由某一类型的值组成</span></span><br><span class="line">PropTypes.shape(对象): <span class="comment">//属性必须是对象，并且满足指定的对象要求</span></span><br><span class="line">PropTypes.exact(&#123;...&#125;)：<span class="comment">//对象必须精确匹配传递的数据</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//自定义属性检查，如果有错误，返回错误对象即可</span></span><br><span class="line">属性: <span class="function"><span class="keyword">function</span>(<span class="params">props, propName, componentName</span>) </span>&#123;</span><br><span class="line">   <span class="comment">//...</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
</ul>
<hr>
<h3 id="5-Ref"><a href="#5-Ref" class="headerlink" title="5.Ref"></a>5.Ref</h3><h4 id="（1）定义-1"><a href="#（1）定义-1" class="headerlink" title="（1）定义"></a>（1）定义</h4><ul>
<li>作用位置：<ul>
<li>作用于内置html元素：得到的是真实DOM元素</li>
<li>作用于类组件：得到的是组件实例对象</li>
<li>不能作用于函数组件</li>
</ul>
</li>
<li>作用形式：<ul>
<li>字符串：<ul>
<li>给组件定义一个ref属性，属性值为字符串str，代表该组件ref存储位置的变量名str</li>
<li>通过this.refs对象的str属性获取ref</li>
<li>不建议使用</li>
</ul>
</li>
<li>对象：<ul>
<li>通过React.createRef()创建一个对象obj，该对象本质就是一个普通对象，拥有一个current属性，属性值为null，给组件定义一个ref属性，属性值为该对象obj</li>
<li>通过传递的对象obj.current获得ref</li>
</ul>
</li>
<li>函数：<ul>
<li>给组件定义一个ref属性，属性值为一个函数func<ul>
<li>该函数会在componentDidMount()调用一次</li>
<li>如果给ref属性重新赋值一个新函数，则旧函数和新函数会在componentWillUpdate()之前分别调用一次</li>
<li>该函数会在componentWillUnMount()调用一次</li>
</ul>
</li>
<li>通过传递的函数func的第一个参数获得ref</li>
</ul>
</li>
</ul>
</li>
</ul>
<h4 id="（2）转发"><a href="#（2）转发" class="headerlink" title="（2）转发"></a>（2）转发</h4><ul>
<li>需求：不期望获得组件本身，而是获得组件内部的子元素</li>
<li>实现：使用高阶组件React.forwardRef()进行ref转发<ul>
<li>参数：接受一个函数组件funcComp</li>
<li>返回值：一个新函数组件newFuncComp<ul>
<li>给新组件newFuncComp定义ref</li>
<li>该ref会被高阶组件React.forwardRef()传递给被包装的组件funcComp的第二个参数</li>
<li>在组件funcComp内通过第二个参数获得ref，并自定义ref指向（或赋值或指向子元素ref）</li>
<li>若ref被指向子元素ref，高阶组件使用者就可以获得函数组件内部的子元素真实DOM或组件实例对象</li>
</ul>
</li>
</ul>
</li>
<li>拓展：<ul>
<li>不使用高阶组件React.forwardRef()也可以使用一个普通属性实现（只是不能定义为ref属性）</li>
<li>高阶组件React.forwardRef()不接受类组件，使用一个函数将其包装一下即可</li>
<li>对自定义高阶组件实现ref转发</li>
</ul>
</li>
</ul>
<hr>
<h3 id="6-render-Props"><a href="#6-render-Props" class="headerlink" title="6.render Props"></a>6.render Props</h3><ul>
<li>组件功能及其处理逻辑一致，只是显示有差异，则可以通过以下方法解决：<ul>
<li>HOC高阶组件提取功能</li>
<li>render props渲染属性<ul>
<li>给render属性传递一个函数，组件内部调用此函数<ul>
<li>函数参数为数据对象</li>
<li>函数返回值为渲染的内容</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<hr>
<h2 id="（四）上下文"><a href="#（四）上下文" class="headerlink" title="（四）上下文"></a>（四）上下文</h2><h3 id="1-特点"><a href="#1-特点" class="headerlink" title="1.特点"></a>1.特点</h3><ul>
<li>某个组件创建了上下文，上下文中的数据会被所有后代组件共享</li>
<li>某个组件依赖了上下文，该组件则不再纯粹（复用性变低，数据管理变复杂）</li>
<li>通常情况下，上下文用于第三方组件（通用组件）</li>
</ul>
<h3 id="2-React-lt-16-0-0版本"><a href="#2-React-lt-16-0-0版本" class="headerlink" title="2.React &lt; 16.0.0版本"></a>2.React &lt; 16.0.0版本</h3><h4 id="（1）创建"><a href="#（1）创建" class="headerlink" title="（1）创建"></a>（1）创建</h4><ul>
<li>只有类组件可以创建上下文</li>
<li>给类组件定义静态属性 static childContextTypes = {} 约束上下文中的数据类型</li>
<li>给类组件定义实例方法 getChildContext()<ul>
<li>该方法会在render()后被自动调用</li>
<li>方法返回值 Object, 定义上下文中的数据，必须满足类型约束</li>
</ul>
</li>
</ul>
<h4 id="（2）获取"><a href="#（2）获取" class="headerlink" title="（2）获取"></a>（2）获取</h4><ul>
<li>给组件定义静态属性 contextTypes = {} 声明并约束需要使用的数据和类型（通常提取类型约定childContextTypes和contextTypes必须保持一致）</li>
<li>在类组件构造函数constructor(props, context)中第二个参数即可获得上下文对象（该对象只包含声明过的数据，并非全部）<ul>
<li>将context交给super(props, context)</li>
<li>在组建内即可使用this.context获得上下文对象</li>
</ul>
</li>
<li>在函数组件中直接从第二个参数获得上下文对象</li>
</ul>
<h4 id="（3）改变"><a href="#（3）改变" class="headerlink" title="（3）改变"></a>（3）改变</h4><ul>
<li>上下文的改变不可以直接改变，源于状态和属性的改变而改变（状态和属性的改变则会重新渲染，渲染后getChildContext()会被自动调用，保持最新上下文）</li>
<li>若子组件使用者想实现改变上下文，通过上下文提供方法，子组件通过调用方法，让父组件创建者自己去改变数据</li>
</ul>
<h4 id="（4）多个上下文"><a href="#（4）多个上下文" class="headerlink" title="（4）多个上下文"></a>（4）多个上下文</h4><ul>
<li>组件不会从自身创建的上下文中去获取数据</li>
<li>组件获取是就近原则，从最近的上下文中优先获取</li>
</ul>
<h3 id="3-React-gt-16-0-0版本"><a href="#3-React-gt-16-0-0版本" class="headerlink" title="3.React &gt;= 16.0.0版本"></a>3.React &gt;= 16.0.0版本</h3><h4 id="（1）上下文是一个独立的对象，使用React-createContext-创建"><a href="#（1）上下文是一个独立的对象，使用React-createContext-创建" class="headerlink" title="（1）上下文是一个独立的对象，使用React.createContext()创建"></a>（1）上下文是一个独立的对象，使用React.createContext()创建</h4><ul>
<li>参数：Object, 默认值</li>
<li>返回值：Object, 上下文对象<ul>
<li><strong>Provider属性：生产者</strong><ul>
<li>一个组件，包裹上下文区域（包裹子元素）</li>
<li>创建上下文，该组件value属性给上下文赋予数据</li>
</ul>
</li>
<li><strong>Consumer属性：消费者</strong><ul>
<li>一个组件，当做子元素使用</li>
<li>该组件children属性值接受一个函数<ul>
<li>函数第一个参数即获得上下文对象</li>
<li>函数返回值会被渲染</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h4 id="（2）多个上下文对应多个上下文对象"><a href="#（2）多个上下文对应多个上下文对象" class="headerlink" title="（2）多个上下文对应多个上下文对象"></a>（2）多个上下文对应多个上下文对象</h4><ul>
<li>Provider禁止复用，应重新React.createContext()创建</li>
<li>创建者和使用者应对应同一个上下文对象<ul>
<li>contextType == React.createContext()</li>
<li>context.Provider &lt;==&gt; context.Consumer</li>
</ul>
</li>
</ul>
<h4 id="（3）context-Provider的value属性发生变化会强制更新"><a href="#（3）context-Provider的value属性发生变化会强制更新" class="headerlink" title="（3）context.Provider的value属性发生变化会强制更新"></a>（3）context.Provider的value属性发生变化会强制更新</h4><ul>
<li>其包裹区域所有元素会被强制重新渲染，无论子元素是否使用上下文</li>
<li>无视性能优化，shouldComponentUpdate()不会被执行</li>
<li>value变化比较的是地址（Object.is()）</li>
<li>通过保持value属性值的引用不变而避免强制更新（优化性能）</li>
<li>在类组件中如果想实现手动强制刷新，调用this.forceUpdate()函数即可</li>
</ul>
<hr>
<h2 id="（五）错误与渲染"><a href="#（五）错误与渲染" class="headerlink" title="（五）错误与渲染"></a>（五）错误与渲染</h2><h3 id="1-错误边界（React-gt-16-0-0）"><a href="#1-错误边界（React-gt-16-0-0）" class="headerlink" title="1.错误边界（React &gt;= 16.0.0）"></a>1.错误边界（React &gt;= 16.0.0）</h3><ul>
<li>在React中，如果某个元素在渲染期间出现了错误，则整个组件树会被卸载</li>
<li>利用错误边界处理错误，自定义一个高阶组件，有能力捕获子元素在渲染期间发生的错误并阻止其继续传播<ul>
<li>方法1：编写静态生命周期函数 static getDerivedStateFromError()<ul>
<li>参数：错误对象</li>
<li>返回值：一个对象Object，该对象会与状态进行混合</li>
<li>触发条件：只有子组件在渲染期间发生错误，才会运行该函数</li>
<li>触发时间：在渲染子组件过程中，发生错误后，更新页面之前运行</li>
<li>处理错误：有机会预先通过状态来处理错误</li>
</ul>
</li>
<li>方法2：编写生命周期函数 componentDidCatch()<ul>
<li>参数1：错误对象</li>
<li>参数2：错误摘要</li>
<li>触发条件：只有子组件在渲染期间发生错误，才会运行该函数</li>
<li>触发时间：在渲染子组件过程中，发生错误后，更新页面之后运行（运行时间点靠后，如果改变状态，性能低下）</li>
<li>处理错误：在生命周期函数内改变状态，有机会预先通过状态来处理错误（通常只用于记录错误信息）</li>
</ul>
</li>
</ul>
</li>
</ul>
<hr>
<h3 id="2-节点创建与挂载"><a href="#2-节点创建与挂载" class="headerlink" title="2.节点创建与挂载"></a>2.节点创建与挂载</h3><ul>
<li>react元素：通过React.createElement()创建的对象</li>
<li>react节点：根据react元素创建用于渲染UI页面的对象</li>
<li>通过节点对象生成虚拟DOM树<ul>
<li>根据不同的节点类型做不同的事情</li>
<li>对于文本节点，关联React节点与真实文本节点</li>
<li>对于DOM节点，关联React节点与真实DOM节点，设置真实DOM的各种属性</li>
<li>对于类组件节点，关联React节点与实例对象，运行生命周期方法<ul>
<li>对render()返回的节点内容进行操作</li>
<li>将componentDidMount()加入执行队列</li>
</ul>
</li>
</ul>
</li>
<li>将生成的虚拟DOM树保存起来，供后续使用</li>
<li>将真实的DOM节点添加到容器中，然后运行执行队列（子组件的componentDidMount()会先运行）</li>
</ul>
<table>
<thead>
<tr>
<th align="left">react元素类型</th>
<th align="left">非react元素类型</th>
<th align="left">react节点类型</th>
<th align="left">react节点创建</th>
<th align="left">后续操作</th>
</tr>
</thead>
<tbody><tr>
<td align="left">string（内置组件）</td>
<td align="left">/</td>
<td align="left">DOM节点</td>
<td align="left">document.createElement()</td>
<td align="left">操作子元素</td>
</tr>
<tr>
<td align="left">function（函数组件）</td>
<td align="left">/</td>
<td align="left">组件节点</td>
<td align="left">调用函数得到节点内容</td>
<td align="left">操作节点内容</td>
</tr>
<tr>
<td align="left">class（类组件）</td>
<td align="left">/</td>
<td align="left">组件节点</td>
<td align="left">创建该类的实例对象</td>
<td align="left">运行生命周期</td>
</tr>
<tr>
<td align="left">/</td>
<td align="left">string（字符串）</td>
<td align="left">文本节点</td>
<td align="left">docuemnt.createTextNode()</td>
<td align="left">/</td>
</tr>
<tr>
<td align="left">/</td>
<td align="left">number（数字）</td>
<td align="left">文本节点</td>
<td align="left">docuemnt.createTextNode()</td>
<td align="left">/</td>
</tr>
<tr>
<td align="left">/</td>
<td align="left">boolean（布尔值）</td>
<td align="left">空节点</td>
<td align="left">占位</td>
<td align="left">/</td>
</tr>
<tr>
<td align="left">/</td>
<td align="left">null（空）</td>
<td align="left">空节点</td>
<td align="left">占位</td>
<td align="left">/</td>
</tr>
<tr>
<td align="left">/</td>
<td align="left">undefined（未定义）</td>
<td align="left">空节点</td>
<td align="left">占位</td>
<td align="left">/</td>
</tr>
<tr>
<td align="left">/</td>
<td align="left">array（数组）</td>
<td align="left">数组节点</td>
<td align="left">docuemnt.createDocumentFragment()</td>
<td align="left">操作数组项</td>
</tr>
</tbody></table>
<hr>
<h3 id="3-节点更新与卸载"><a href="#3-节点更新与卸载" class="headerlink" title="3.节点更新与卸载"></a>3.节点更新与卸载</h3><h4 id="（1）更新场景与流程："><a href="#（1）更新场景与流程：" class="headerlink" title="（1）更新场景与流程："></a>（1）更新场景与流程：</h4><ul>
<li>ReactDOM.render()根节点开始更新<ul>
<li>进入根节点的 <strong><font color=red>对比更新（diff）</font></strong></li>
</ul>
</li>
<li>setState()以该实例对象所在的组件节点为根节点的分支开始更新<ul>
<li>运行生命周期：static getDerivedStateFromProps()</li>
<li>运行生命周期：shouldComponentUpdate()<ul>
<li>返回值：false ==&gt; 结束</li>
<li>返回值：true ==&gt; 继续更新</li>
</ul>
</li>
<li>运行生命周期：render()<ul>
<li>得到一个新节点，进入新节点的 <strong><font color=red>对比更新（diff）</font></strong></li>
</ul>
</li>
<li>将生命周期加入队列：getSnapshotBeforeUpdate()</li>
<li>将生命周期加入队列：componentDidUpdate()</li>
</ul>
</li>
<li>更新虚拟DOM树</li>
<li>更新真实DOM</li>
<li>执行队列中的生命周期：componentDidMount()()</li>
<li>执行队列中的生命周期：getSnapshotBeforeUpdate()</li>
<li>执行队列中的生命周期：componentDidUpdate()</li>
<li>运行生命周期：componentWillUnMount()</li>
</ul>
<h4 id="（2）对比更新"><a href="#（2）对比更新" class="headerlink" title="（2）对比更新"></a>（2）对比更新</h4><ul>
<li>本质：将产生的新节点与之前虚拟DOM树中的节点进行对比，发现差异，完成更新</li>
<li>问题：与之前虚拟DOM树中的哪个节点对比？</li>
<li>假设：<ul>
<li>节点不会出现层次移动，利用树的深度直接定位层级</li>
<li>同一层级不同节点类型会生成不同的结构</li>
<li>同一层级相同节点类型的多个兄弟节点使用Key进行标识<ul>
<li>同一层级没有key，节点按照顺序对比</li>
<li>同一层级若有key，节点按key确定对比目标（key不同直接走没有对比目标）</li>
</ul>
</li>
</ul>
</li>
<li>结果：<ul>
<li>找到了对比目标，判断节点类型<ul>
<li>类型相同：针对类型做 <strong><font color=green>对应更新</font></strong></li>
<li>类型不同：**<font color=blue>卸载旧节点</font>**，创建新节点</li>
</ul>
</li>
<li>没有找到对比目标，判断节点的增减<ul>
<li>创建增加的节点，走创建流程</li>
<li>卸载多余的节点，走卸载流程</li>
</ul>
</li>
</ul>
</li>
</ul>
<h4 id="（3）对应更新"><a href="#（3）对应更新" class="headerlink" title="（3）对应更新"></a>（3）对应更新</h4><ul>
<li>若之前虚拟DOM树中React节点有关联真实DOM，则重用关联的真实DOM，记录变化的属性</li>
<li>若之前虚拟DOM树中React节点有关联实例对象，则重用关联的实例对象，运行生命周期方法</li>
<li>函数组件节点：直接调用函数，递归对比更新</li>
<li>空节点：不做任何事</li>
<li>数组节点：遍历数组，逐一递归对比更新</li>
</ul>
<h4 id="（4）卸载节点"><a href="#（4）卸载节点" class="headerlink" title="（4）卸载节点"></a>（4）卸载节点</h4><ul>
<li>先创建新节点，再卸载旧节点，然后挂载新节点</li>
<li>非类组件节点：直接放弃该节点，如果有子节点，递归卸载子节点</li>
<li>类组件节点：<ul>
<li>直接放弃该节点，如果有子节点，递归卸载子节点</li>
<li>运行声明周期：componentWillUnMount()</li>
<li>在卸载过程中componentWillUnMount()不会加入队列而是直接执行</li>
<li>先卸载当前节点再递归卸载子节点，当前节点componentWillUnMount()会先运行</li>
</ul>
</li>
<li>不同类型的节点会假设生成不同的结构<ul>
<li>父节点不同，整个分支会被卸载重建</li>
<li>子节点没有机会进行对比更新</li>
<li>应尽量不要去改变节点类型</li>
</ul>
</li>
<li>在虚拟DOM树中是按位置进行对比的<ul>
<li>节点在树中的位置变化直接影响对比对象会发生变化</li>
<li>应尽量利用样式控制节点的显示隐藏</li>
<li>应充分利用空节点保持结构的稳定</li>
</ul>
</li>
</ul>
<hr>
<h3 id="4-Profiler调试工具"><a href="#4-Profiler调试工具" class="headerlink" title="4.Profiler调试工具"></a>4.Profiler调试工具</h3><ul>
<li>可用于性能分析 </li>
</ul>
<hr>
<h2 id="（六）HOOK"><a href="#（六）HOOK" class="headerlink" title="（六）HOOK"></a>（六）HOOK</h2><h3 id="1-State-Hook"><a href="#1-State-Hook" class="headerlink" title="1.State Hook"></a>1.State Hook</h3><h4 id="（1）注册"><a href="#（1）注册" class="headerlink" title="（1）注册"></a>（1）注册</h4><ul>
<li>API：React.useState()</li>
<li>功能：为函数组件添加状态，只能在函数内部使用</li>
<li>参数：Any，状态默认值（默认undefined）</li>
<li>返回值：Array，一个长度为2的数组<ul>
<li>数组第一项：状态数据</li>
<li>数组第一项：状态改变方法</li>
</ul>
</li>
</ul>
<h4 id="（2）原理"><a href="#（2）原理" class="headerlink" title="（2）原理"></a>（2）原理</h4><ul>
<li>第一次创建节点的时候给组件节点创建一个状态表格</li>
<li>在第n次调用useState()，检查状态表格是否存在下标n<ul>
<li>不存在：使用默认值创建一个状态，加入状态表格，下标为n</li>
<li>若存在：忽略默认值，直接返回下标为n的状态</li>
</ul>
</li>
<li>每个组件的状态表格是独立的，互不影响</li>
<li>一个组件可有多个状态，状态应定义在函数体顶部，便于阅读</li>
<li>严禁在代码块（判断、循环）内定义，会导致状态对应紊乱</li>
<li>状态对应的改变方法的引用是固定的，节约内存空间</li>
<li>调用状态改变方法改变状态，状态数据不会混合，而是直接覆盖替换，建议对多个数据使用多个状态，分别管理</li>
<li>某些状态之间没有必然联系，应分化为不同的状态，而不要合在一起</li>
<li>状态发生改变，组件会被重现渲染，但是调用状态改变方法，若数据没有变化（Object.is(old, new)）不会导致重现渲染</li>
<li>如果要实现强制刷新，可使用默认值为空对象的状态改变方法 const [, forceUpdate] = useState({})</li>
<li>状态的改变可能是异步的，对状态改变方法传递一个函数，函数参数是上一次的状态且是可信任的</li>
</ul>
<hr>
<h3 id="2-Effect-Hook"><a href="#2-Effect-Hook" class="headerlink" title="2.Effect Hook"></a>2.Effect Hook</h3><h4 id="（1）注册-1"><a href="#（1）注册-1" class="headerlink" title="（1）注册"></a>（1）注册</h4><ul>
<li>API：<ul>
<li>React.useEffect()</li>
<li>React.useLayoutEffect()</li>
</ul>
</li>
<li>功能：为函数组件注册副作用处理函数，只能在函数内部使用</li>
<li>参数1：function，副作用处理函数<ul>
<li>参数：undefined，没有参数</li>
<li>返回值：function，清理函数</li>
</ul>
</li>
<li>参数2：Array，依赖项<ul>
<li>使用一个空数组作为依赖项，则副作用处理函数仅会在首次渲染时运行一次，清理函数仅会在组件销毁时运行一次</li>
</ul>
</li>
<li>返回值：undefined，没有返回值</li>
</ul>
<h4 id="（2）副作用处理函数"><a href="#（2）副作用处理函数" class="headerlink" title="（2）副作用处理函数"></a>（2）副作用处理函数</h4><ul>
<li>运行时间点：<ul>
<li>React.useEffect()：<ul>
<li>副作用处理函数在修改真实DOM之后，界面UI完成渲染之后异步运行</li>
<li>推荐使用React.useEffect()，不会导致页面渲染阻塞</li>
</ul>
</li>
<li>React.useLayoutEffect()：<ul>
<li>类组件生命周期方法在修改真实DOM之后，界面UI尚未渲染之前同步运行</li>
<li>与类组件中componentDidMount()、componentDidUpdate()一致</li>
</ul>
</li>
<li>如果注册了依赖项，只有依赖数据发生变化才会运行</li>
</ul>
</li>
<li>注册副作用处理函数与State类似<ul>
<li>严禁在代码块（判断、循环）内注册</li>
<li>一个组件可以注册多个副作用处理函数</li>
<li>多个副作用函数按照注册顺序依次执行</li>
</ul>
</li>
<li><font color=red>在副作用函数内使用了函数上下文中的数据，由于闭包影响，数据更新可能会非实时</font><ul>
<li>副作用处理函数是异步函数，函数内使用外部上下文中的数据状态会指向定义时的状态，而非调用时的状态</li>
<li>如果在定义到调用期间使用的数据状态发生了改变，则调用时的结果可能会不如预期</li>
</ul>
</li>
<li>副作用函数的重复注册执行的是覆盖，应保持副作用函数和清理函数的稳定</li>
</ul>
<h4 id="（3）清理函数"><a href="#（3）清理函数" class="headerlink" title="（3）清理函数"></a>（3）清理函数</h4><ul>
<li>副作用处理函数可以有返回值，返回一个函数，叫做清理函数</li>
<li>清理函数会在合适的时候被自动调用：<ul>
<li>组件首次渲染时不会运行</li>
<li>组件销毁时会运行</li>
<li>在每次副作用处理函数运行之前运行</li>
<li>如果注册了依赖项，只有在组件销毁时才会运行</li>
</ul>
</li>
</ul>
<hr>
<h3 id="3-自定义-Hook"><a href="#3-自定义-Hook" class="headerlink" title="3.自定义 Hook"></a>3.自定义 Hook</h3><ul>
<li>API：React.useHookName()</li>
<li>功能：使用一个函数提取封装通用Hook功能</li>
<li>语法：使用use前缀命名</li>
<li>优势：对比高阶组件和render Props<ul>
<li>用函数封装功能，使用和理解更容易</li>
<li>不会改变组件结构，没有复杂的嵌套结构</li>
<li>Hook可以进行自定义分化，将复杂的数据和功能拆分，横切关注点</li>
</ul>
</li>
</ul>
<h3 id="4-Context-Hook"><a href="#4-Context-Hook" class="headerlink" title="4.Context Hook"></a>4.Context Hook</h3><ul>
<li>API：React.useContext()</li>
<li>功能：用于获取上下文中的数据</li>
<li>目的：减少组件嵌套层次（替代Consumer）</li>
<li>参数：Object，上下文对象（React.createContext()的返回值）</li>
<li>返回值：Object，上下文中的数据（由上层最近的Provider的value决定）</li>
</ul>
<h3 id="5-Callback-Hook"><a href="#5-Callback-Hook" class="headerlink" title="5.Callback Hook"></a>5.Callback Hook</h3><ul>
<li>API：React.useCallback()</li>
<li>功能：用于固定函数引用（通常用于固定回调函数）</li>
<li>目的：用于优化组件事件（组件事件是一个属性，如若传递的函数引用不固定会导致组件重新渲染而浪费效率）</li>
<li>参数1：function，需要固定的函数</li>
<li>参数2：Array，依赖项</li>
<li>返回值：function，固定引用的函数<ul>
<li>只要依赖项没有变化，函数引用就不会改变</li>
<li>依赖项没有变化， useCallback()就会忽略参数，继续返回上一次的返回值 </li>
</ul>
</li>
</ul>
<h3 id="6-Memo-Hook"><a href="#6-Memo-Hook" class="headerlink" title="6.Memo Hook"></a>6.Memo Hook</h3><ul>
<li>API：React.useMemo()</li>
<li>功能：用于稳定处理函数的结果（通常用于稳定复杂计算的结果）</li>
<li>目的：用于优化性能</li>
<li>参数1：function，处理函数</li>
<li>参数2：Array，依赖项</li>
<li>返回值：Any，处理函数的返回值<ul>
<li>只要依赖项没有变化，处理函数就不会再次调用</li>
<li>依赖项没有变化， 处理函数的返回值作为useMemo()的返回值固定不变</li>
</ul>
</li>
<li>特点：比useCallback()更加强大：<ul>
<li>useCallback()只能固定函数</li>
<li>useMemo()可以固定任意类型的数据</li>
</ul>
</li>
</ul>
<h3 id="6-Ref-Hook"><a href="#6-Ref-Hook" class="headerlink" title="6.Ref Hook"></a>6.Ref Hook</h3><ul>
<li>API：React.useRef()</li>
<li>功能：用于创建一个不可变的ref对象（通常用于固定ref引用）</li>
<li>目的：在函数组件内代替React.cteateRef()</li>
<li>参数：Any，默认值对应ref对象中current属性的值</li>
<li>返回值：Object，ref对象{current: null}</li>
<li>特点：ref对象引用不可变，但是current属性值是可变的，可用于保存任何可变值</li>
</ul>
<hr>
<h3 id="7-Reducer-Hook"><a href="#7-Reducer-Hook" class="headerlink" title="7.Reducer Hook"></a>7.Reducer Hook</h3><h4 id="1-注册"><a href="#1-注册" class="headerlink" title="1.注册"></a>1.注册</h4><ul>
<li>API：React.useReducer()</li>
<li>功能：封装Flux数据流处理模式</li>
<li>目的：在组件内只分发action声明如何处理数据，而不关注数据处理逻辑和过程</li>
<li>参数1：function，数据处理函数reducer</li>
<li>参数2：Any，数据State默认值（如果注册了第三个参数，则该默认值会作为参数而非数据默认值）</li>
<li>参数3：function，数据State默认值处理函数<ul>
<li>参数：Any，注册的第二个参数</li>
<li>返回值：Any，数据State默认值</li>
</ul>
</li>
<li>返回值：Array，数据和action分发函数[state, dispatch]</li>
</ul>
<h4 id="2-原理"><a href="#2-原理" class="headerlink" title="2.原理"></a>2.原理</h4><ul>
<li>模式：遵从Flux数据流处理模式</li>
<li>数据：仓库数据或状态state</li>
<li>action: Object，数据处理描述对象<ul>
<li>type属性：声明数据处理方式（与reducer约定对应）</li>
<li>payload属性：附加数据</li>
</ul>
</li>
<li>reducer：function，数据处理逻辑<ul>
<li>参数1：Any，数据State</li>
<li>参数2：Object，action数据处理描述对象</li>
<li>返回值：处理后的数据</li>
</ul>
</li>
<li>dispatch：function，任务分发器<ul>
<li>参数：Object，action数据处理描述对象</li>
<li>函数体：<ul>
<li>调用reducer处理函数，将数据Stae和action传入</li>
<li>得到reducer处理结果，将结果作为数据改变就数据Stae状态</li>
</ul>
</li>
</ul>
</li>
<li>useReducer：function，封装函数<ul>
<li>创建一个状态State作为数据仓库，得到一个对应的状态修改方法setState()</li>
<li>状态默认值来源于参数传入</li>
<li>定义dispatch函数，在dispatch函数内实现数据状态的改变<ul>
<li>数据处理逻辑reducer()来源于参数传入</li>
<li>数据改变方法setState()来源于创建状态时对应的改变方法</li>
<li>新数据来源于数据处理函数reducer()的调用结果</li>
<li>给数据处理函数reducer()传递的数据仓库来源于创建的状态State</li>
<li>给数据处理函数reducer()传递的action来源于外部使用dispatch时分发的action</li>
</ul>
</li>
<li>返回一个数组：<ul>
<li>第一项：数据状态State</li>
<li>第二项：dispatch函数</li>
</ul>
</li>
</ul>
</li>
</ul>
<hr>
<h1 id="三、React-Transition-Group-动画"><a href="#三、React-Transition-Group-动画" class="headerlink" title="三、React Transition Group 动画"></a>三、React Transition Group 动画</h1><p><a target="_blank" rel="noopener" href="https://reactcommunity.org/react-transition-group/">React Transition Group文档 </a></p>
<blockquote>
<p>yarn add react-transition-group</p>
</blockquote>
<h2 id="（一）Transition"><a href="#（一）Transition" class="headerlink" title="（一）Transition"></a>（一）Transition</h2><h3 id="1-原理"><a href="#1-原理" class="headerlink" title="1.原理"></a>1.原理</h3><ul>
<li>默认情况下，Transition组件不会更改其渲染的组件的行为，它仅跟踪组件的“进入”和“退出”状态。</li>
<li>由您来赋予这些状态以意义和效果。</li>
<li>可以在组件进入或退出时为其添加样式。</li>
<li>初始状态：<ul>
<li>当in属性为false时，初始状态为exited</li>
<li>当in属性为true时，初始状态为entered</li>
</ul>
</li>
<li>进入状态：<ul>
<li>当in属性从false变化到true</li>
<li>立即执行默认状态exited</li>
<li>立即执行正在进入entering</li>
<li>延时timeout时间后，执行已完成进入entered</li>
</ul>
</li>
<li>退出状态：<ul>
<li>当in属性从true变化到false</li>
<li>立即执行默认状态entered</li>
<li>立即执行正在退出exiting</li>
<li>延时timeout时间后，执行已完成退出exited</li>
</ul>
</li>
</ul>
<h3 id="2-属性"><a href="#2-属性" class="headerlink" title="2.属性"></a>2.属性</h3><ul>
<li>in：boolean，用于决定状态</li>
<li>timeout：number，用于决定状态变化时长</li>
<li>mountOnEnter：boolean，是否延迟挂载子组件<ul>
<li>false：默认与父组件Transition同时挂载</li>
<li>true：当in指定为true时才会挂载</li>
</ul>
</li>
<li>unmountOnExit：boolean，是否在退出后卸载载子组件<ul>
<li>false：默认当状态为exited时，子组件依然挂载</li>
<li>true：当状态为exited时，子组件会被卸载</li>
</ul>
</li>
<li>appear：boolean，首次挂载是否应用过渡状态<ul>
<li>false：默认首次挂载组件没有应用过渡状态</li>
<li>true：在组件挂在后，会立即应用过渡状态</li>
</ul>
</li>
<li>其它属性</li>
<li>其它事件</li>
</ul>
<h3 id="3-状态"><a href="#3-状态" class="headerlink" title="3.状态"></a>3.状态</h3><ul>
<li>通过Transition组件的children使用一个函数，函数参数state获得实时状态<ul>
<li>‘entering’ 正在进入</li>
<li>‘entered’ 已完成进入</li>
<li>‘exiting’ 正在退出</li>
<li>‘exited’ 已完成退出</li>
</ul>
</li>
</ul>
<hr>
<h2 id="（二）CSSTransition"><a href="#（二）CSSTransition" class="headerlink" title="（二）CSSTransition"></a>（二）CSSTransition</h2><h3 id="1-原理-1"><a href="#1-原理-1" class="headerlink" title="1.原理"></a>1.原理</h3><ul>
<li>建立在Transition组件的基础上，完全继承了Transition组件的特性</li>
<li>将Transition组件过渡状态变化对应为CSSTransition根子元素设置className类</li>
<li>通过className类定义对应的类样式</li>
</ul>
<h3 id="2-属性-1"><a href="#2-属性-1" class="headerlink" title="2.属性"></a>2.属性</h3><ul>
<li>属性对应Transition组件</li>
<li>事件对应Transition组件</li>
</ul>
<h3 id="3-className类"><a href="#3-className类" class="headerlink" title="3.className类"></a>3.className类</h3><table>
<thead>
<tr>
<th align="left">Transition组件过渡状态</th>
<th align="left">CSSTransition根子元素类样式</th>
</tr>
</thead>
<tbody><tr>
<td align="left">‘entering’ 正在进入</td>
<td align="left">‘enter enter-active’</td>
</tr>
<tr>
<td align="left">‘entered’ 已完成进入</td>
<td align="left">‘enter-done’</td>
</tr>
<tr>
<td align="left">‘exiting’ 正在退出</td>
<td align="left">‘exit exit-active’</td>
</tr>
<tr>
<td align="left">‘exited’ 已完成退出</td>
<td align="left">‘exit-done’</td>
</tr>
<tr>
<td align="left">‘appear’ 首次挂载</td>
<td align="left">‘appear’</td>
</tr>
<tr>
<td align="left">‘appearing’ 首次挂载中</td>
<td align="left">‘appear appear-active’</td>
</tr>
<tr>
<td align="left">‘appeared’ 首次挂载完成</td>
<td align="left">‘appear-done enter-done’</td>
</tr>
</tbody></table>
<ul>
<li>当in属性从false变化为true时：<ul>
<li>立即添加类样式：enter（强制回流）</li>
<li>立即添加类样式：enter-active</li>
<li>延时timeout时间后，移除类样式enter、enter-active，添加类样式enter-done</li>
</ul>
</li>
<li>当in属性从true变化为false时：<ul>
<li>立即添加类样式：exit（强制回流）</li>
<li>立即添加类样式：exit-active</li>
<li>延时timeout时间后，移除类样式exit、exit-active，添加类样式exit-done</li>
</ul>
</li>
<li>使用classNames属性修改对应类样式名称<ul>
<li>字符串：添加前缀</li>
<li>对象：具体修改类样式名称</li>
</ul>
</li>
<li><a target="_blank" rel="noopener" href="https://animate.style/">与css动画库animate.css联用</a></li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">classNames=&#123;&#123;</span><br><span class="line">   <span class="attr">appear</span>: <span class="string">&#x27;my-appear&#x27;</span>,</span><br><span class="line">   <span class="attr">appearActive</span>: <span class="string">&#x27;my-active-appear&#x27;</span>,</span><br><span class="line">   <span class="attr">appearDone</span>: <span class="string">&#x27;my-done-appear&#x27;</span>,</span><br><span class="line">   <span class="attr">enter</span>: <span class="string">&#x27;my-enter&#x27;</span>,</span><br><span class="line">   <span class="attr">enterActive</span>: <span class="string">&#x27;my-active-enter&#x27;</span>,</span><br><span class="line">   <span class="attr">enterDone</span>: <span class="string">&#x27;my-done-enter&#x27;</span>,</span><br><span class="line">   <span class="attr">exit</span>: <span class="string">&#x27;my-exit&#x27;</span>,</span><br><span class="line">   <span class="attr">exitActive</span>: <span class="string">&#x27;my-active-exit&#x27;</span>,</span><br><span class="line">   <span class="attr">exitDone</span>: <span class="string">&#x27;my-done-exit&#x27;</span>,</span><br><span class="line">&#125;&#125;</span><br></pre></td></tr></table></figure>
<hr>
<h2 id="（三）SwitchTransition"><a href="#（三）SwitchTransition" class="headerlink" title="（三）SwitchTransition"></a>（三）SwitchTransition</h2><ul>
<li>children属性接受一个Transition或CSSTransition组件，主要实现有次序的切换<ul>
<li>Transition或CSSTransition组件不再使用in属性</li>
<li>Transition或CSSTransition组件使用key属性</li>
<li>控制Transition或CSSTransition组件根子元素的样式</li>
<li>当key值发生变化的时候，重现渲染Transition或CSSTransition组件根子元素（DOM元素）</li>
</ul>
</li>
<li>model属性控制切换模式<ul>
<li>out-in<ul>
<li>当key值发生变化的时候</li>
<li>为DOM元素添加退出样式exit、exit-active</li>
<li>退出完成后，将DOM元素移除</li>
<li>重现渲染DOM元素</li>
<li>为新DOM元素素添加进入样式enter、enter-active、enter-done</li>
</ul>
</li>
<li>in-out<ul>
<li>当key值发生变化的时候</li>
<li>重现渲染DOM元素（保留原DOM元素）</li>
<li>为DOM元素添加进入样式enter、enter-active、enter-done</li>
<li>为原DOM元素添加退出样式exit、exit-active</li>
<li>退出完成后，将原DOM元素移除</li>
</ul>
</li>
</ul>
</li>
</ul>
<hr>
<h2 id="（四）TransitionGroup"><a href="#（四）TransitionGroup" class="headerlink" title="（四）TransitionGroup"></a>（四）TransitionGroup</h2><ul>
<li>children属性接受多个Transition或CSSTransition组件，主要实现一组（列表）动画</li>
<li><a target="_blank" rel="noopener" href="https://www.npmjs.com/package/uuid">使用uuid定义唯一的key值</a></li>
<li>当一个DOM元素移除时会应用退出类样式</li>
<li>当一个DOM元素添加时会应用进入类样式</li>
<li>appear属性：可统一控制整个列表首次挂载应用进入样式</li>
<li>component属性：控制TransitionGroup在组件树中生成的结构<ul>
<li>默认生成一个div</li>
<li>字符串：指定生成的元素，例如“ul”</li>
<li>null：不生成任何元素</li>
</ul>
</li>
</ul>
<hr>
<h1 id="四、React-Router-路由"><a href="#四、React-Router-路由" class="headerlink" title="四、React Router 路由"></a>四、React Router 路由</h1><p><a target="_blank" rel="noopener" href="http://react-guide.github.io/react-router-cn/index.html">React Router</a></p>
<p><a target="_blank" rel="noopener" href="https://github.com/ReactTraining/react-router/tree/master/packages/react-router-dom#installation">React Router Dom</a></p>
<blockquote>
<p>yarn add react-router-dom</p>
</blockquote>
<h2 id="（一）概述"><a href="#（一）概述" class="headerlink" title="（一）概述"></a>（一）概述</h2><h3 id="1-单页面应用"><a href="#1-单页面应用" class="headerlink" title="1.单页面应用"></a>1.单页面应用</h3><ul>
<li>通常只是站点的一部分（某一个功能块）</li>
<li>路由：<ul>
<li>根据不同的页面地址，展示不同的组件</li>
<li>实现无刷新地址切换</li>
</ul>
</li>
</ul>
<h3 id="2-url地址"><a href="#2-url地址" class="headerlink" title="2.url地址"></a>2.url地址</h3><ul>
<li>协议名（schema）</li>
<li>主机名（host）<ul>
<li>IP地址</li>
<li>预设值：localhost</li>
<li>域名</li>
<li>局域网电脑名称</li>
</ul>
</li>
<li>端口号（port）<ul>
<li>http：默认80</li>
<li>https：默认443</li>
</ul>
</li>
<li>路径（path）</li>
<li>地址参数（search、query）</li>
<li>哈希、锚点（hash）</li>
</ul>
<h3 id="3-路由模式"><a href="#3-路由模式" class="headerlink" title="3.路由模式"></a>3.路由模式</h3><ul>
<li>Hash Router 哈希路由<ul>
<li>url地址中hash值的改变不会导致页面的属性</li>
<li>根据hash值来确定渲染的组件</li>
<li>使用location对象的hash属性获得hash值</li>
</ul>
</li>
<li>Browser History Router 浏览器历史记录路由<ul>
<li>history历史记录使用栈stack存储</li>
<li>html5新增history API使浏览器可以改变url地址而不刷新页面<ul>
<li>history.pushState(data, title, url)向历史记录栈中添加一条url记录</li>
<li>history.replaceState(data, title, url)将当前指向的url记录替换为指定的url记录</li>
</ul>
</li>
<li>根据页面路径来确定渲染的组件</li>
</ul>
</li>
</ul>
<hr>
<h2 id="（二）路由组件"><a href="#（二）路由组件" class="headerlink" title="（二）路由组件"></a>（二）路由组件</h2><h3 id="1-Router-模式组件"><a href="#1-Router-模式组件" class="headerlink" title="1.Router 模式组件"></a>1.Router 模式组件</h3><ul>
<li>HashRouter组件，哈希路由模式</li>
<li>BrowserRouter组件，浏览器历史记录路由模式<ul>
<li>Router组件<ul>
<li>Router.Provider组件，提供上下文支持<ul>
<li>value包含三个数据对象（仅组件内部使用，且是包装过的）<ul>
<li>history</li>
<li>location</li>
<li>match</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li>getUserConfirmation属性：function，阻塞器函数</li>
</ul>
</li>
</ul>
<h3 id="2-Route-规则组件"><a href="#2-Route-规则组件" class="headerlink" title="2.Route 规则组件"></a>2.Route 规则组件</h3><ul>
<li>Route组件，路由配置<ul>
<li>Router.Consumer组件，获得路由上下文<ul>
<li>Router.Provider组件，提供局部上下文</li>
</ul>
</li>
<li>path属性：<ul>
<li>string，匹配路径</li>
<li>string-pattern，匹配规则</li>
<li>array，一组匹配路径（匹配其一即可）</li>
<li>不配置path属性，任意匹配</li>
</ul>
</li>
<li>sensitive属性：boolean，是否区分大小写</li>
<li>exact属性：boolean，是否精确匹配</li>
<li>strict属性：boolean，是够严格匹配最后一个斜杠/</li>
<li>component属性：element，定义匹配后渲染的组件</li>
<li>render属性：function，定义匹配后运行的函数，渲染返回值</li>
<li>children属性<ul>
<li>React元素：只要当前Route进行了匹配，无论是否匹配成功，子元素都会渲染，并且会忽略component属性</li>
<li>function函数：<ul>
<li>参数：路由上下文</li>
<li>返回值：只要当前Route进行了匹配，无论是否匹配成功，返回值都会渲染，并且会忽略component属性</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="3-功能组件"><a href="#3-功能组件" class="headerlink" title="3.功能组件"></a>3.功能组件</h3><ul>
<li><strong>Switch组件</strong>，控制一组Route组件，只要匹配到一个即停止匹配</li>
<li><strong>withRouter高阶组件</strong>，向非路由组件中注入路由信息</li>
<li><strong>Link组件</strong>，生成一个无刷新跳转的a元素<ul>
<li>to属性：<ul>
<li>string：路径</li>
<li>object：自定义location对象，会自动解析到地址栏</li>
</ul>
</li>
<li>replace属性：boolean，是否使用replace方式跳转</li>
<li>innerRef属性：DOM，对应内部真实a元素</li>
</ul>
</li>
<li><strong>NavLink组件</strong>，强化的Link组件，添加匹配时类样式<ul>
<li>activeClassName属性：string，自定义匹配时类样式（默认active）</li>
<li>activeStyle属性：object，匹配时行间样式</li>
</ul>
</li>
<li><strong>Redirect组件</strong>，强化的Link组件，重定向（当该组件运行时直接跳转至to属性定义的地址）<ul>
<li>to属性：路径</li>
<li>push属性：是否使用push方式跳转</li>
<li>from属性：跳转条件（当匹配到from属性时才进行跳转）</li>
</ul>
</li>
</ul>
<hr>
<h2 id="（三）路由信息"><a href="#（三）路由信息" class="headerlink" title="（三）路由信息"></a>（三）路由信息</h2><h3 id="1-创建"><a href="#1-创建" class="headerlink" title="1.创建"></a>1.创建</h3><ul>
<li>Router组件会创建上下文，并注入信息</li>
<li>Route组件也会创建上下文，并注入信息</li>
</ul>
<h3 id="2-获取"><a href="#2-获取" class="headerlink" title="2.获取"></a>2.获取</h3><ul>
<li>上下文对于开发者是不可用的</li>
<li>Route组件在匹配成功后，将上下文中的信息作为属性传递给对应的组件</li>
<li>通过组件属性获得对应的路由信息<ul>
<li>props.history</li>
<li>props.location</li>
<li>props.match</li>
</ul>
</li>
</ul>
<h3 id="3-history对象"><a href="#3-history对象" class="headerlink" title="3.history对象"></a>3.history对象</h3><ul>
<li><strong>实现无刷新地址跳转</strong></li>
<li>该对象是包装过的，不是原生的window.history对象<ul>
<li>如果直接使用原生history对象，则无法支持哈希路由模式</li>
<li>原生history对象方法使用时不会有任何通知，React无法知晓地址变化，不会重现渲染组件</li>
</ul>
</li>
<li>push方法：将新的地址入栈<ul>
<li>参数1：新路径</li>
<li>参数2：附加state数据<ul>
<li>通过history.location.state获取</li>
<li>此数据依赖跳转时手动附加，如果直接访问某个地址则无法拥有状态数据，所以数据通常附带在url地址中，而不是使用此处的附加state</li>
</ul>
</li>
</ul>
</li>
<li>replace方法：将新地址替换当前地址<ul>
<li>参数1：新路径</li>
<li>参数2：附加state数据</li>
</ul>
</li>
<li>go方法</li>
<li>forward方法</li>
<li>back方法</li>
<li>listen方法：监听器<ul>
<li>参数：function，当地址变化时调用该函数（即将跳转到新页面之前）<ul>
<li>参数1：location对象，当前地址信息</li>
<li>参数2：action字符串，进入地址方式<ul>
<li>“POP” ：浏览器前进后退、history.go()、history.goBack()、history.goForward()</li>
<li>“PUSH” ：history.push()</li>
<li>“REPLACE” ：history.replace()</li>
</ul>
</li>
</ul>
</li>
<li>返回值：function，调用此函数取消监听</li>
</ul>
</li>
<li>block()方法：阻塞器<ul>
<li>参数：阻塞提示信息<ul>
<li>string</li>
<li>function<ul>
<li>参数1：location对象</li>
<li>参数2：action类型</li>
<li>返回值：string</li>
</ul>
</li>
</ul>
</li>
<li>调用getUserConfirmation()<ul>
<li>参数1：string，阻塞提示信息</li>
<li>参数2：function，是否放行<ul>
<li>放行：调用并传递true</li>
<li>阻塞：调用并传递false</li>
</ul>
</li>
</ul>
</li>
<li>返回值：function，调用此函数取消阻塞</li>
</ul>
</li>
</ul>
<h3 id="4-location"><a href="#4-location" class="headerlink" title="4.location"></a>4.location</h3><ul>
<li><strong>地址栏信息</strong></li>
<li>与history.location是同一个对象</li>
<li>hash属性：哈希值</li>
<li>pathname属性：路径</li>
<li>search属性：search数据</li>
<li>state属性：附加状态数据</li>
<li><a target="_blank" rel="noopener" href="https://github.com/sindresorhus/query-string#readme">使用query-string库解析字符串</a></li>
</ul>
<h3 id="5-match"><a href="#5-match" class="headerlink" title="5.match"></a>5.match</h3><ul>
<li><strong>路由匹配信息</strong></li>
<li>path属性：匹配规则</li>
<li>url属性：真实url地址中匹配到的部分</li>
<li>isExact属性：是否是精确匹配（指的是匹配结果是否精确，而非匹配方式是否精确，与Route组件定义exact属性无关）</li>
<li>params属性：对应string-pattern匹配规则中的数据</li>
<li><a target="_blank" rel="noopener" href="https://github.com/pillarjs/path-to-regexp#readme">path-to-regexp库实现string-pattern匹配规则</a></li>
</ul>
<hr>
<h2 id="（四）路由应用"><a href="#（四）路由应用" class="headerlink" title="（四）路由应用"></a>（四）路由应用</h2><h3 id="1-嵌套路由"><a href="#1-嵌套路由" class="headerlink" title="1.嵌套路由"></a>1.嵌套路由</h3><ul>
<li>通过父组件传递的属性location.url简化内层路由path</li>
<li>使用配置对象简化路由path</li>
</ul>
<h3 id="2-权限保护"><a href="#2-权限保护" class="headerlink" title="2.权限保护"></a>2.权限保护</h3><ul>
<li>封装一个自定义路由ProtectedRoute，使用方法与Route一样</li>
<li>返回一个Route组件</li>
<li>将component、render、children除外的属性传递给Route</li>
<li>Route组件使用render函数</li>
<li>在函数内部进行授权处理<ul>
<li>有权，则render直接返回component进行渲染</li>
<li>无权，则使用Redirect组件进行重定向</li>
</ul>
</li>
<li>在Redirect组件进行重定向进行重定向的时候，附带当前地址</li>
<li>在完成登录后，获取附带数据中的地址进行跳回</li>
<li>如果附带数据中没有跳转地址，则直接跳转至某个页面（通常是首页）</li>
</ul>
<h3 id="3-导航守卫"><a href="#3-导航守卫" class="headerlink" title="3.导航守卫"></a>3.导航守卫</h3><ul>
<li>离开一个页面，进入另一个页面时，触发的事件</li>
<li>使用history.listen方法添加一个监听器<ul>
<li>参数：function，监听器函数<ul>
<li>监听器的参数可以获得新location信息和action类型</li>
<li>监听器外部history.location获得旧的location信息</li>
</ul>
</li>
<li>返回值：function，卸载一个监听器</li>
</ul>
</li>
<li>使用history.block()方法添加一个阻塞器<ul>
<li>传递阻塞提示信息</li>
<li>调用阻塞器函数，并传递msg阻塞消息和callback放行函数</li>
<li>调用放行函数，传递true放行，传递false阻塞</li>
</ul>
</li>
</ul>
<h3 id="4-路由动画"><a href="#4-路由动画" class="headerlink" title="4.路由动画"></a>4.路由动画</h3><h3 id="5-滚动条复位"><a href="#5-滚动条复位" class="headerlink" title="5.滚动条复位"></a>5.滚动条复位</h3><h3 id="6-阻止跳转"><a href="#6-阻止跳转" class="headerlink" title="6.阻止跳转"></a>6.阻止跳转</h3><hr>
<h1 id="五、Redux-数据管理"><a href="#五、Redux-数据管理" class="headerlink" title="五、Redux 数据管理"></a>五、Redux 数据管理</h1><p><a target="_blank" rel="noopener" href="https://redux.js.org/api/api-reference">redux官方文档</a></p>
<blockquote>
<p>yard add redux</p>
</blockquote>
<h2 id="（一）Redux-核心"><a href="#（一）Redux-核心" class="headerlink" title="（一）Redux 核心"></a>（一）Redux 核心</h2><h3 id="1-MVC解决方案"><a href="#1-MVC解决方案" class="headerlink" title="1.MVC解决方案"></a>1.MVC解决方案</h3><ul>
<li>它是一个UI的解决方案，用于降低UI复杂度，以及UI关联的数据复杂度</li>
<li><strong>传统的服务端MVC</strong><ul>
<li>服务端响应一个完整的HTML页面</li>
<li>该HTML中包含页面所需要的数据</li>
<li>浏览器仅仅承担渲染的作用<img src="./MVC.png"></li>
</ul>
</li>
<li>Controller 处理请求，组装这次请求所需要的数据</li>
<li>Model 处理数据用于UI渲染的数据模型</li>
<li>View 试图，将数据模型组装到页面中</li>
<li><font color=red>不适用于前端（用户场景太多，控制太复杂）</font></li>
</ul>
<h3 id="2-FLUX解决方案"><a href="#2-FLUX解决方案" class="headerlink" title="2.FLUX解决方案"></a>2.FLUX解决方案</h3><ul>
<li>facebook提出的数据解决方案，他的最大历史意义在于它引入了action概念</li>
<li>action是一个普通的对象，用于描述干什么，action.type必须是一个String类型</li>
<li>store数据仓库，用于存储数据</li>
</ul>
<h3 id="3-Redux解决方案"><a href="#3-Redux解决方案" class="headerlink" title="3.Redux解决方案"></a>3.Redux解决方案</h3><ul>
<li>在flux基础上引入reducer<img src="./redux.png"></li>
<li>自定义reducer数据处理程序<ul>
<li>类型：function</li>
<li>参数1：旧state</li>
<li>参数2：action</li>
<li>返回值：新state</li>
</ul>
</li>
<li>自定义action数据处理描述<ul>
<li>类型：object</li>
<li>type属性：描述</li>
<li>payload属性：附带数据</li>
</ul>
</li>
<li>创建数据仓库store<ul>
<li>从redux引入createStore  </li>
<li>store = createStore(reducer, state)创建数据仓库</li>
</ul>
</li>
<li>分发action：store.dispatch(action)</li>
<li>获取数据：store.getState()</li>
</ul>
<h3 id="4-action"><a href="#4-action" class="headerlink" title="4.action"></a>4.action</h3><ul>
<li>action必须是一个plain-object(平面对象，它的__proto__指向Object.prototype)</li>
<li>action必须有一个type属性（any类型）<ul>
<li>大中型项目中避免硬编码, 可以使用type文件形式的样板代码</li>
</ul>
</li>
<li>action可以有一个payload属性（附加数据）</li>
<li>为了方便传递action，通常会使用action创建函数来创建action<ul>
<li>创建函数应该是一个无副作用的纯函数，该函数返回一个action对象</li>
</ul>
</li>
<li>为了方便利用action创建函数来分发，可以使用 bindActionCreators<ul>
<li>bindActionCreators用于增强action的功能，不仅可以创建action，并且在创建action后自动完成分发</li>
<li>bindActionCreators第一个参数接受一个对象，对象的属性对应action创建函数</li>
<li>bindActionCreators第二个参数接受一个dispatch，用于指定是哪一个用dispatch来完成分发</li>
<li>bindActionCreators返回一个对象，对象方法与接受的第一个参数对象相同，调用该对象的方法即完成使用对应的action进行分发</li>
</ul>
</li>
</ul>
<h3 id="5-reducer"><a href="#5-reducer" class="headerlink" title="5.reducer"></a>5.reducer</h3><ul>
<li>reducer必须为一个纯函数，用于处理对应的action触发时如何处理数据</li>
<li>reducer调用：<ul>
<li>store.dispatch分发的时候</li>
<li>createStore初始化仓库的时候</li>
<li>初始化仓库时可以不使用默认state，而是在reducer中给一个默认值</li>
</ul>
</li>
<li>reducer内部通常使用switch来判断action.type</li>
<li>通常一个工程只有一个store, 一个store只有一个reduce<ul>
<li>为了方便管理，通常将reducer放到单独的文件中</li>
<li>在大中型项目中，操作和结构都比较复杂，需要对reducer进行细分，每一个状态对应一个处理函数reducer</li>
<li>最用将细分的reducer进行合并，使用创建对象的形式执行处理函数，并单独传递对应的数据</li>
<li>combineReducers就是将多个细分的reducer进行合并成一个reducer，用于创建store<ul>
<li>combineReducers参数接受一个对象，对象属性对应细分的reducer</li>
<li>combineReducers返回一个最终的reducer</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="6-store"><a href="#6-store" class="headerlink" title="6.store"></a>6.store</h3><ul>
<li>通过createStore创建，用于保存数据</li>
<li>dispathch方法：分发action</li>
<li>getState方法：获取仓库数据</li>
<li>replaceReducer方法：替换数据处理程序reducer</li>
<li>subscribe方法：数据变化监听器（返回一个函数用于取消监听）</li>
</ul>
<h3 id="7-redux-actions"><a href="#7-redux-actions" class="headerlink" title="7.redux-actions"></a>7.redux-actions</h3><p><a target="_blank" rel="noopener" href="https://redux-actions.js.org/">redux-actions 官方文档</a></p>
<blockquote>
<p>yarn add redux-actions</p>
</blockquote>
<ul>
<li><p><strong>createAction方法</strong>：创建一个action创建函数</p>
<ul>
<li>参数1：action.type</li>
<li>参数2：payload处理函数<ul>
<li>参数：action创建函数传递的参数</li>
<li>返回值：payload的值</li>
</ul>
</li>
<li>返回值：一个对应的action创建函数</li>
</ul>
</li>
<li><p><strong>createActions方法</strong>：创建一组action创建函数</p>
<ul>
<li>参数：object，action描述对象<ul>
<li>属性名：action.type（遵循大写、下划线分割）</li>
<li>属性值：payload处理函数（不需要payload则设置为null）</li>
</ul>
</li>
<li>返回值：object，对应的action创建函数<ul>
<li>属性名：对应action创建函数名（转换为小驼峰命名）</li>
<li>属性值：对应action创建函数</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>handleAction方法</strong>：创建处理单个action类型的reducer函数</p>
<ul>
<li>参数1：action.type（支持action创建函数名，重写了toString）</li>
<li>参数2：针对action.type匹配处理函数</li>
<li>参数3：state默认值</li>
</ul>
</li>
<li><p><strong>handleAction方法</strong>：创建处理多个action类型的reducer函数</p>
<ul>
<li>参数：object，映射规则<ul>
<li>属性名：action.type（遵循大写、下划线分割）</li>
<li>属性值：针对action.type匹配处理函数</li>
</ul>
</li>
<li>返回值：function，reducer处理函数</li>
</ul>
</li>
<li><p><strong>combineActions方法</strong>：用于配合createActions和handleActions，将多个action创建函数合并成一个，对应一个处理函数reducer</p>
<ul>
<li>参数：需要匹配的action创建函数</li>
<li>返回值：一个合并的函数</li>
</ul>
</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> getActions = createActions(&#123;</span><br><span class="line">  <span class="attr">INCREASE</span>: <span class="function">() =&gt;</span> <span class="number">1</span>,</span><br><span class="line">  <span class="attr">DECREASE</span>: <span class="function">() =&gt;</span> -<span class="number">1</span>,</span><br><span class="line">  <span class="attr">ADD</span>: <span class="function"><span class="params">n</span> =&gt;</span> n,</span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">export</span> &#123;increase, decrease add&#125; = getActions</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> handleActions(&#123;</span><br><span class="line">  [combineActions(increse, decrease, add)]: <span class="function">(<span class="params">state, &#123;type, payload&#125;</span>) =&gt;</span> state + payload</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>
<hr>
<h2 id="（二）Middleware-中间件"><a href="#（二）Middleware-中间件" class="headerlink" title="（二）Middleware 中间件"></a>（二）Middleware 中间件</h2><h3 id="1-自定义中间件"><a href="#1-自定义中间件" class="headerlink" title="1.自定义中间件"></a>1.自定义中间件</h3><h4 id="（1）原理"><a href="#（1）原理" class="headerlink" title="（1）原理"></a>（1）原理</h4><ul>
<li>更改dispatch函数<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> store = createStore(reducer)</span><br><span class="line"><span class="keyword">const</span> dispatch = store.dispatch</span><br><span class="line"><span class="comment">//添加一个中间件1</span></span><br><span class="line">store.dispatch = <span class="function">(<span class="params">action</span>) =&gt;</span> &#123;</span><br><span class="line">  store.getState()<span class="comment">//旧数据</span></span><br><span class="line">  action<span class="comment">//action</span></span><br><span class="line">  dispatch()<span class="comment">//运行原有功能</span></span><br><span class="line">  store.getState()<span class="comment">//新数据</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//添加一个中间件2</span></span><br><span class="line">dispatch = store.dispatch</span><br><span class="line">store.dispatch = <span class="function">(<span class="params">action</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="comment">//中间件功能</span></span><br><span class="line">  dispatch()<span class="comment">//运行中间件1</span></span><br><span class="line">  <span class="comment">//中间件功能</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="（2）中间件函数"><a href="#（2）中间件函数" class="headerlink" title="（2）中间件函数"></a>（2）中间件函数</h4></li>
<li>中间件是一个函数<ul>
<li>参数：store仓库</li>
<li>返回值：dispatch创建函数<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> store = createStore(reducer)</span><br><span class="line"><span class="comment">//中间件1</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">middleware</span>(<span class="params">store</span>)</span>&#123;<span class="comment">//得到仓库</span></span><br><span class="line">  <span class="keyword">return</span> <span class="function">(<span class="params">nextDispatch</span>) =&gt;</span> &#123;<span class="comment">//得到下一个中间件的dispatch</span></span><br><span class="line">    <span class="keyword">return</span> <span class="function">(<span class="params">action</span>) =&gt;</span> &#123;<span class="comment">//得到action</span></span><br><span class="line">      <span class="comment">//中间件功能</span></span><br><span class="line">      nextDispatch(action)</span><br><span class="line">      <span class="comment">//中间件功能</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> middleware = <span class="function"><span class="params">store</span> =&gt;</span> <span class="function"><span class="params">nextDispatch</span> =&gt;</span> <span class="function"><span class="params">action</span> =&gt;</span> &#123;</span><br><span class="line">  <span class="comment">//中间件功能</span></span><br><span class="line">  nextDispatch(action)</span><br><span class="line">  <span class="comment">//中间件功能</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
</ul>
</li>
</ul>
<h4 id="（3）applyMiddleWare-应用中间件函数"><a href="#（3）applyMiddleWare-应用中间件函数" class="headerlink" title="（3）applyMiddleWare() 应用中间件函数"></a>（3）applyMiddleWare() 应用中间件函数</h4><ul>
<li>参数：中间件函数</li>
<li>返回值：用作createStore(reducer, applyMiddleWare(中间件))的第二或第三个参数</li>
<li>应用的中间件会在创建store后运行<img src="./Middleware.png"></li>
</ul>
<hr>
<h3 id="2-redux-logger-日志记录"><a href="#2-redux-logger-日志记录" class="headerlink" title="2.redux-logger 日志记录"></a>2.redux-logger 日志记录</h3><p><a target="_blank" rel="noopener" href="https://github.com/LogRocket/redux-logger#readme">redux-logger 日志记录</a></p>
<blockquote>
<p>yard add redux-logger</p>
</blockquote>
<ul>
<li>打印日志记录</li>
<li>createLogger支持自定义日志记录打印<ul>
<li>collapsed: 日志是否折叠</li>
<li>duration：是否打印时间</li>
<li>predicate: 自定义处理函数</li>
</ul>
</li>
<li>logger中间件应放置于最后</li>
</ul>
<h3 id="3-redux-thunk-副作用处理"><a href="#3-redux-thunk-副作用处理" class="headerlink" title="3.redux-thunk 副作用处理"></a>3.redux-thunk 副作用处理</h3><p><a target="_blank" rel="noopener" href="https://github.com/reduxjs/redux-thunk/redux-logger#readme">redux-thunk 副作用处理</a></p>
<blockquote>
<p>yard add redux-thunk</p>
</blockquote>
<ul>
<li>允许action是一个带有副作用的函数</li>
<li>当action是一个函数被分发时，thunk会阻止action继续向后提交<ul>
<li>thunk会向函数中传递三个参数<ul>
<li>dispatch：来自于store.dispatch</li>
<li>getState: 来自于store.getState</li>
<li>extra: 来自于注册thunk时传递的额外参数（withExtraArgument）</li>
</ul>
</li>
</ul>
</li>
<li>logger中间件应放置于最前</li>
</ul>
<h3 id="4-redux-promise-副作用处理"><a href="#4-redux-promise-副作用处理" class="headerlink" title="4.redux-promise 副作用处理"></a>4.redux-promise 副作用处理</h3><p><a target="_blank" rel="noopener" href="https://github.com/redux-utilities/redux-promise">redux-promise 副作用处理</a></p>
<blockquote>
<p>yard add redux-promise</p>
</blockquote>
<ul>
<li>允许action或action.payload是一个promise对象</li>
<li>当action是一个promise对象时，会等待promise完成，将promise结果作为action进行触发</li>
<li>当action.payload是一个promise对象时，会等待promise完成，将promise结果作为payload进行触发</li>
<li>promise中使用resolve来触发action</li>
</ul>
<h3 id="5-redux-saga-副作用处理"><a href="#5-redux-saga-副作用处理" class="headerlink" title="5.redux-saga 副作用处理"></a>5.redux-saga 副作用处理</h3><p><a target="_blank" rel="noopener" href="https://redux-saga-in-chinese.js.org/">redux-saga 副作用处理</a></p>
<blockquote>
<p>yard add redux-saga</p>
</blockquote>
<img src="./saga.png">

<table>
<thead>
<tr>
<th align="left">saga指令</th>
<th align="left">指令功能</th>
<th align="left">指令参数</th>
<th align="left">yield结果</th>
<th align="left">是否阻塞</th>
<th align="left">特点</th>
</tr>
</thead>
<tbody><tr>
<td align="left">all()</td>
<td align="left">合并多个任务</td>
<td align="left">array：生成器集合</td>
<td align="left">/</td>
<td align="left">阻塞</td>
<td align="left">等待运行所有生成器运行结束</td>
</tr>
<tr>
<td align="left">race()</td>
<td align="left">多个任务竞赛</td>
<td align="left">array：生成器集合</td>
<td align="left">/</td>
<td align="left">阻塞</td>
<td align="left">等待第一个结束的生成器运行结束</td>
</tr>
<tr>
<td align="left">take()</td>
<td align="left">监听action触发</td>
<td align="left">action.type</td>
<td align="left">action对象</td>
<td align="left">阻塞</td>
<td align="left">只监听1次</td>
</tr>
<tr>
<td align="left">takeEvery()</td>
<td align="left">监听action触发</td>
<td align="left">action.type、callback处理程序</td>
<td align="left">/</td>
<td align="left">无阻塞</td>
<td align="left">持续监听，不断开启新任务</td>
</tr>
<tr>
<td align="left">takeLastest()</td>
<td align="left">监听action触发</td>
<td align="left">action.type、callback处理程序</td>
<td align="left">/</td>
<td align="left">无阻塞</td>
<td align="left">持续监听，自动取消之前的任务</td>
</tr>
<tr>
<td align="left">delay()</td>
<td align="left">延时</td>
<td align="left">number：timeout</td>
<td align="left">/</td>
<td align="left">阻塞</td>
<td align="left">/</td>
</tr>
<tr>
<td align="left">put()</td>
<td align="left">触发action</td>
<td align="left">object：action对象</td>
<td align="left">/</td>
<td align="left">无阻塞</td>
<td align="left">/</td>
</tr>
<tr>
<td align="left">select</td>
<td align="left">获取仓库数据state</td>
<td align="left">function：数据筛选函数</td>
<td align="left">仓库数据state</td>
<td align="left">无阻塞</td>
<td align="left">/</td>
</tr>
<tr>
<td align="left">call()</td>
<td align="left">调用异步函数</td>
<td align="left">异步函数、依赖参数</td>
<td align="left">函数调用结果</td>
<td align="left">可能阻塞</td>
<td align="left">如果是promise会阻塞</td>
</tr>
<tr>
<td align="left">apply()</td>
<td align="left">调用异步函数</td>
<td align="left">this指向、异步函数、依赖参数</td>
<td align="left">函数调用结果</td>
<td align="left">可能阻塞</td>
<td align="left">如果是promise会阻塞</td>
</tr>
<tr>
<td align="left">cps()</td>
<td align="left">调用异步函数</td>
<td align="left">异步函数、依赖参数</td>
<td align="left">函数调用结果</td>
<td align="left">可能阻塞</td>
<td align="left">针对回调模式的异步</td>
</tr>
<tr>
<td align="left">promise对象</td>
<td align="left">等待promise完成</td>
<td align="left">/</td>
<td align="left">promise结果</td>
<td align="left">阻塞</td>
<td align="left">不推荐，应统一使用指令</td>
</tr>
<tr>
<td align="left">fork()</td>
<td align="left">任务分支</td>
<td align="left">生成器函数</td>
<td align="left">Task对象</td>
<td align="left">无阻塞</td>
<td align="left">/</td>
</tr>
<tr>
<td align="left">cancel()</td>
<td align="left">取消一个或多个任务</td>
<td align="left">Task对象</td>
<td align="left">Task对象</td>
<td align="left">无阻塞</td>
<td align="left">/</td>
</tr>
<tr>
<td align="left">cancelled()</td>
<td align="left">当前任务是否被取消</td>
<td align="left">/</td>
<td align="left">boolean</td>
<td align="left">无阻塞</td>
<td align="left">/</td>
</tr>
</tbody></table>
<hr>
<h2 id="（三）React-Redux-连接redux和react"><a href="#（三）React-Redux-连接redux和react" class="headerlink" title="（三）React-Redux 连接redux和react"></a>（三）React-Redux 连接redux和react</h2><p><a target="_blank" rel="noopener" href="https://www.redux.org.cn/docs/react-redux/">连接redux和react</a></p>
<blockquote>
<p>yarn add react-redux</p>
</blockquote>
<h3 id="1-Provider组件"><a href="#1-Provider组件" class="headerlink" title="1.Provider组件"></a>1.Provider组件</h3><ul>
<li>将redux的store仓库放到一个上下文中</li>
<li>通过store属性提供store仓库</li>
</ul>
<h3 id="2-connect函数"><a href="#2-connect函数" class="headerlink" title="2.connect函数"></a>2.connect函数</h3><ul>
<li>参数1：属性映射函数 mapStateToProps<ul>
<li>参数：传入整个仓库数据state</li>
<li>返回值：映射的数据对象</li>
</ul>
</li>
<li>参数2：事件映射函数 mapDispatchToProps<ul>
<li>参数：会传入dispatch</li>
<li>返回值：映射的事件处理程序对象</li>
</ul>
</li>
<li>返回值：高阶组件<ul>
<li>参数：需要连接的展示组件</li>
<li>返回值：提供数据的容器组件</li>
</ul>
</li>
<li><strong>细节：</strong><ul>
<li>connect的前两个参数是可选的，不要相应映射的时候传递null</li>
<li>connect的第二个参数可以是一个对象，每个属性是一个action创建函数</li>
<li>connect的第二个参数默认不传递，那么链接的组件默认会得到一个dispatch属性，有能力去自己触发action</li>
<li>connnect的后两个参数是可选的，mergeProps用于将要传递的属性进一步处理，options用于配置自定义处理</li>
</ul>
</li>
</ul>
<h3 id="3-connectAdvanced"><a href="#3-connectAdvanced" class="headerlink" title="3.connectAdvanced"></a>3.connectAdvanced</h3><ul>
<li>用于统一处理需要传递的属性</li>
<li>参数：function<ul>
<li>参数：dispatch</li>
<li>返回值：function<ul>
<li>参数：state, props</li>
<li>返回值：object此对象的属性用于传递</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="4-createProvider"><a href="#4-createProvider" class="headerlink" title="4.createProvider"></a>4.createProvider</h3><ul>
<li>通过唯一的key创建一个上下文</li>
<li>通过connect中options的storeKey来确定要使用的上下文</li>
</ul>
<hr>
<h2 id="（四）Connected-React-Router-连接redux和react-router"><a href="#（四）Connected-React-Router-连接redux和react-router" class="headerlink" title="（四）Connected-React-Router 连接redux和react-router"></a>（四）Connected-React-Router 连接redux和react-router</h2><p><a target="_blank" rel="noopener" href="https://github.com/supasate/connected-react-router#readme">连接redux和react-router</a></p>
<blockquote>
<p>yarn add connected-react-router<br>yarn add history</p>
</blockquote>
<h3 id="1-connectRouter方法"><a href="#1-connectRouter方法" class="headerlink" title="1.connectRouter方法"></a>1.connectRouter方法</h3><ul>
<li>用于创建一个reducer</li>
<li>参数：需要一个history对象</li>
<li>返回值：一个reducer</li>
<li>在combineReducers中使用router对应connectRouter创建的reducer</li>
</ul>
<h3 id="2-routerMiddleware方法"><a href="#2-routerMiddleware方法" class="headerlink" title="2.routerMiddleware方法"></a>2.routerMiddleware方法</h3><ul>
<li>用于创建一个中间件</li>
<li>参数：需要一个history对象</li>
<li>返回值：一个Middleware</li>
<li>在applyMiddleware中使用率先使用此中间件（位于第一个）</li>
</ul>
<h3 id="3-ConectedRouter组件"><a href="#3-ConectedRouter组件" class="headerlink" title="3.ConectedRouter组件"></a>3.ConectedRouter组件</h3><ul>
<li>用于创建一个路由上下文</li>
<li>替代BrowserRouter和HashRouter</li>
<li>上下文中使用react-router路由跳转的时候会自动触发action</li>
<li>若使用Connected-React-Router中的跳转，则默认得到的是action创建函数<ul>
<li>push()：创建一个action</li>
<li>repalce()：创建一个action</li>
</ul>
</li>
<li>使用react-redux中connect进行链接<ul>
<li>通过事件映射dispatch触发action进行跳转</li>
</ul>
</li>
</ul>
<hr>
<h1 id="六、Dva-js"><a href="#六、Dva-js" class="headerlink" title="六、Dva-js"></a>六、Dva-js</h1><img src="./dva.png">

<p><a target="_blank" rel="noopener" href="https://dvajs.com/">dva官方文档</a></p>
<blockquote>
<p>yarn add dva</p>
</blockquote>
<ul>
<li>整合：<ul>
<li>react</li>
<li>react-dom</li>
<li>redux</li>
<li>redux-saga</li>
<li>react-redux</li>
<li>connected-react-router</li>
</ul>
</li>
</ul>
<h3 id="1-配置部分-dvaObj"><a href="#1-配置部分-dvaObj" class="headerlink" title="1.配置部分 dvaObj"></a>1.配置部分 dvaObj</h3><ul>
<li>dva()创建一个dva对象<ul>
<li>参数：object<ul>
<li>history：配置history对象</li>
<li>initialState: 配置创建仓库时默认数据</li>
<li>onError: 全局错误捕捉函数，传递错误信息error和dispatch函数</li>
<li>onAction：配置中间件（中间件对象或数组）</li>
<li>onStateChange: 仓库数据状态变化监听函数，传递最新状态</li>
<li>onReducer: 传递一个reducer，返回一个reducer函数，在每个reducer即将运行前触发</li>
<li>onEffect: 默认effect包装函数替换方案</li>
<li>extraReducers：额外附加的reducer，一个对象，每个方法是一个reducer</li>
<li>extraEnhancers: 默认createStore方法的增强方案，一个数组，每一项是一个函数</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="2-组件部分-react"><a href="#2-组件部分-react" class="headerlink" title="2.组件部分 react"></a>2.组件部分 react</h3><ul>
<li>dvaObj.router()定义渲染内容<ul>
<li>参数：function<ul>
<li>参数1：dvaObj</li>
<li>参数2：history</li>
</ul>
</li>
<li>返回值：渲染内容</li>
</ul>
</li>
<li>dvaObj.start()定义项目启动<ul>
<li>参数：css选择器（document.querySelector）</li>
</ul>
</li>
</ul>
<h3 id="3-数据部分-redux"><a href="#3-数据部分-redux" class="headerlink" title="3.数据部分 redux"></a>3.数据部分 redux</h3><ul>
<li>dvaObj.model()定义渲染内容<ul>
<li>参数：object<ul>
<li>namespace</li>
<li>state</li>
<li>reducers</li>
<li>effects</li>
<li>subscriptions</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="4-路由部分-router"><a href="#4-路由部分-router" class="headerlink" title="4.路由部分 router"></a>4.路由部分 router</h3><ul>
<li>相关的导出路径 ‘dva/router’</li>
<li>默认完成connectRouter：传入history, 配置reducer</li>
<li>默认完成routerMiddleware：传入history, 配置redux中间件</li>
<li>自行处理ConnectedRouter：传入history, 配置router上下文<ul>
<li>在创建dva对象时配置history</li>
<li>在调用router时候，dva默认会给routerConfig函数传递dva对象和history对象</li>
<li>在使用routerRedux的ConnectedRouter组件替代BrowserRouter或HashRouter并传递一个history属性</li>
</ul>
</li>
</ul>
<h3 id="5-插件部分-use"><a href="#5-插件部分-use" class="headerlink" title="5.插件部分 use"></a>5.插件部分 use</h3><ul>
<li>dvaObj.use()使用插件</li>
</ul>
<hr>
<h1 id="七、Umi-js"><a href="#七、Umi-js" class="headerlink" title="七、Umi-js"></a>七、Umi-js</h1><p><a target="_blank" rel="noopener" href="https://umijs.org/zh-CN">umi.js官方文档</a></p>
<blockquote>
<p>yarn global add umi</p>
</blockquote>
<h2 id="（一）路由"><a href="#（一）路由" class="headerlink" title="（一）路由"></a>（一）路由</h2><h3 id="1-约定式路由"><a href="#1-约定式路由" class="headerlink" title="1.约定式路由"></a>1.约定式路由</h3><h4 id="（1）匹配"><a href="#（1）匹配" class="headerlink" title="（1）匹配"></a>（1）匹配</h4><ul>
<li>umi约定，使用文件名及文件路径匹配对应的路由</li>
<li>pages目录用于存放页面<ul>
<li>root/pages</li>
<li>root/src/pages</li>
</ul>
</li>
<li>嵌套路由：使用属性中的children来定义内容位置<ul>
<li>全局嵌套<ul>
<li>root/layouts/index.js</li>
<li>root/src/layout/index.js</li>
</ul>
</li>
<li>局部嵌套<ul>
<li>root/pages/_layout.js</li>
<li>root/src/pages/_layout.js</li>
</ul>
</li>
</ul>
</li>
<li>404路由：只有在生产模式启用<ul>
<li>root/pages/404.js</li>
<li>root/src/pages/404.js </li>
</ul>
</li>
<li>动态路由：使用$ + name对应string-pattern规则<ul>
<li>root/pages/$id.js</li>
<li>root/src/pages/$name/$id.js</li>
</ul>
</li>
</ul>
<h4 id="（2）跳转"><a href="#（2）跳转" class="headerlink" title="（2）跳转"></a>（2）跳转</h4><ul>
<li>链接跳转<blockquote>
<p>import Link from ‘umi/link’<br>import NavLink from ‘umi/navlink’</p>
</blockquote>
<ul>
<li>使用Link组件：相当于react-router-dom中Link</li>
<li>使用NavLink组件：相当于react-router-dom中NavLink</li>
</ul>
</li>
<li>代码跳转<blockquote>
<p>import router from ‘umi/router’ </p>
</blockquote>
<ul>
<li>使用router对象<ul>
<li>go方法</li>
<li>goBack方法</li>
<li>goForward方法</li>
<li>push方法</li>
<li>replace方法</li>
</ul>
</li>
</ul>
</li>
</ul>
<h4 id="（3）路由信息"><a href="#（3）路由信息" class="headerlink" title="（3）路由信息"></a>（3）路由信息</h4><ul>
<li>pages、layout目录下的组件：<ul>
<li>使用属性props来获得：<ul>
<li>match<ul>
<li>params属性对应string-pattern规则参数</li>
</ul>
</li>
<li>history</li>
<li>location<ul>
<li>query属性已经使用query-string封装成对象</li>
</ul>
</li>
<li>route</li>
</ul>
</li>
</ul>
</li>
<li>非pages、layout目录下的组件：<ul>
<li>使用withRouter高阶组件<blockquote>
<p>import withRouter from ‘umi/withRouter’</p>
</blockquote>
</li>
</ul>
</li>
</ul>
<h4 id="（4）额外属性配置"><a href="#（4）额外属性配置" class="headerlink" title="（4）额外属性配置"></a>（4）额外属性配置</h4><ul>
<li>使用文档注释：遵循YAML格式，且必须配置于最顶部</li>
<li>键值对格式：不使用引号，且冒号后严格使用空格</li>
<li>数组项使用-并缩进：不使用中括号，且严格使用空格缩进，不支持tab缩进</li>
</ul>
<h3 id="2-配置式路由"><a href="#2-配置式路由" class="headerlink" title="2.配置式路由"></a>2.配置式路由</h3><ul>
<li>优先级高于约定式（一旦配置，约定式全部失效）</li>
<li>配置根目录文件：（其中之一）<ul>
<li>root/.umirc.js</li>
<li>root/config/config.js</li>
</ul>
</li>
<li>配置文件默认导出一个对象，配置route属性，类型是一个数组<ul>
<li>每一项就是一条匹配规则，类型是一个对象<ul>
<li>path：匹配路径</li>
<li>exact：是否精确匹配，默认true</li>
<li>component：渲染组件路径，相对于pages</li>
<li>routes：路由嵌套，一个数组，配置子路由</li>
<li>Routes：预处理<ul>
<li>一个数组，数组项为预处理的高阶组件路径，相对于根目录</li>
<li>渲染第一项，如果使用了children属性：<ul>
<li>将component配置组件作为children属性，传递给数组最后一项</li>
<li>每一项倒序作为children属性依次向前传递，最终渲染第一项</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<hr>
<h2 id="（二）数据"><a href="#（二）数据" class="headerlink" title="（二）数据"></a>（二）数据</h2><h3 id="1-dva管理redux数据"><a href="#1-dva管理redux数据" class="headerlink" title="1.dva管理redux数据"></a>1.dva管理redux数据</h3><blockquote>
<p>import {connect} from ‘umi’</p>
</blockquote>
<ul>
<li>全局定义：<ul>
<li>root/models/namespace.js</li>
<li>root/src/models/namespace.js</li>
</ul>
</li>
<li>局部定义<ul>
<li>root/pages/models/namespace.js</li>
<li>root/src/pages/models/namespace.js</li>
<li>root/src/pages/model.js</li>
</ul>
</li>
<li>文件名即为namespace</li>
</ul>
<h3 id="2-代理服务器解决开发中的跨域"><a href="#2-代理服务器解决开发中的跨域" class="headerlink" title="2.代理服务器解决开发中的跨域"></a>2.代理服务器解决开发中的跨域</h3><ul>
<li>配置.umirc.js文件中proxy对象<ul>
<li>属性名：访问的地址</li>
<li>属性值：object<ul>
<li>target：转发的地址</li>
<li>changeOrgin：是否修改源</li>
</ul>
</li>
</ul>
</li>
<li>让跨域发生在代理服务器与服务器中</li>
</ul>
<h3 id="3-协同开发中数据模拟"><a href="#3-协同开发中数据模拟" class="headerlink" title="3.协同开发中数据模拟"></a>3.协同开发中数据模拟</h3><ul>
<li>使用mock模块<ul>
<li>root/mock/data.js</li>
<li>root/src/pages/_mock.js</li>
</ul>
</li>
<li>默认导出一个对象<ul>
<li>属性名：string, method + url</li>
<li>属性值：any, 模拟数据</li>
</ul>
</li>
</ul>
<hr>
<h2 id="（三）样式"><a href="#（三）样式" class="headerlink" title="（三）样式"></a>（三）样式</h2><h3 id="1-组件私有样式"><a href="#1-组件私有样式" class="headerlink" title="1.组件私有样式"></a>1.组件私有样式</h3><ul>
<li>与组件同目录</li>
<li>导入css时，会通过css-mudle处理为一个对象，从对象属性获得类样式</li>
</ul>
<h3 id="2-局部样式"><a href="#2-局部样式" class="headerlink" title="2.局部样式"></a>2.局部样式</h3><ul>
<li>root/src/assets/css/style.css</li>
<li>导入css时，会通过css-mudle处理为一个对象，从对象属性获得类样式</li>
</ul>
<h3 id="3-全局样式"><a href="#3-全局样式" class="headerlink" title="3.全局样式"></a>3.全局样式</h3><ul>
<li>root/src/global.css</li>
<li>导入css时，不会会通过css-mudle处理，直接使用样式</li>
</ul>
<hr>
<h2 id="（四）配置"><a href="#（四）配置" class="headerlink" title="（四）配置"></a>（四）配置</h2><h2 id="（五）脚手架"><a href="#（五）脚手架" class="headerlink" title="（五）脚手架"></a>（五）脚手架</h2><blockquote>
<p>yarn create umi</p>
</blockquote>
<hr>
<h1 id="八、antDesign"><a href="#八、antDesign" class="headerlink" title="八、antDesign"></a>八、antDesign</h1><p><a target="_blank" rel="noopener" href="https://ant.design/index-cn">antDesign官方文档</a></p>

      
      <!-- 打赏 -->
      
    </div>
    <footer class="article-footer">
      <a data-url="https://gitee.com/huafu123/blog/2018/10/01/REACTa/" data-id="ckya9fc16000qygf6f81ygwmv"
        class="article-share-link">分享</a>
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/blog/tags/js-react/" rel="tag">js react</a></li></ul>

    </footer>

  </div>

  

  
  
  

  

</article>
    
    <article id="post-MOCK" class="article article-type-post" itemscope
  itemprop="blogPost" data-scroll-reveal>

  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/blog/2018/08/01/MOCK/"
    >MockJs 初识</a
  >
</h2>
  

    </header>
    

    
    <div class="article-meta">
      <a href="/blog/2018/08/01/MOCK/" class="article-date">
  <time datetime="2018-08-01T13:01:40.000Z" itemprop="datePublished">2018-08-01</time>
</a>
      
    </div>
    

    

    <div class="article-entry" itemprop="articleBody">
      


      

      
      <ol>
<li><p>安装</p>
<blockquote>
<p>npm install mockjs –save<br>npm install axios –save</p>
</blockquote>
</li>
<li><p>模拟假数据</p>
</li>
</ol>
<ul>
<li>mock.js文件<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> Mock <span class="keyword">from</span> <span class="string">&#x27;mockjs&#x27;</span>;</span><br><span class="line"><span class="keyword">const</span> data = Mock.mock(<span class="string">&#x27;https://www.test.com&#x27;</span>, &#123;</span><br><span class="line">  <span class="string">&quot;userInfo|10&quot;</span>: [&#123;</span><br><span class="line">    <span class="string">&quot;id|+1&quot;</span>: <span class="number">1</span>,</span><br><span class="line">    <span class="string">&quot;name&quot;</span>: <span class="string">&quot;@cname&quot;</span>,</span><br><span class="line">    <span class="string">&quot;age|18-28&quot;</span>: <span class="number">25</span>,</span><br><span class="line">    <span class="string">&quot;sex|1&quot;</span>: [<span class="string">&quot;男&quot;</span>, <span class="string">&quot;女&quot;</span>]</span><br><span class="line">  &#125;]</span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> data;</span><br></pre></td></tr></table></figure></li>
</ul>
<ol start="3">
<li>使用假数据</li>
</ol>
<ul>
<li>index.jsx入口文件<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="string">&#x27;./mock&#x27;</span>;</span><br></pre></td></tr></table></figure></li>
</ul>
<ol start="4">
<li>请求</li>
</ol>
<ul>
<li>需要假数据的文件<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> Axios <span class="keyword">from</span> <span class="string">&#x27;axios&#x27;</span>;</span><br><span class="line">Axios.get(<span class="string">&#x27;https://www.test.com&#x27;</span>).then(<span class="function"><span class="params">res</span> =&gt;</span> <span class="built_in">console</span>.log(res.data))</span><br></pre></td></tr></table></figure></li>
</ul>

      
      <!-- 打赏 -->
      
    </div>
    <footer class="article-footer">
      <a data-url="https://gitee.com/huafu123/blog/2018/08/01/MOCK/" data-id="ckya9fc13000jygf6bqqnb01q"
        class="article-share-link">分享</a>
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/blog/tags/mockjs-axios/" rel="tag">mockjs axios</a></li></ul>

    </footer>

  </div>

  

  
  
  

  

</article>
    
    <article id="post-VUEa" class="article article-type-post" itemscope
  itemprop="blogPost" data-scroll-reveal>

  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/blog/2018/08/01/VUEa/"
    >VUE 初识</a
  >
</h2>
  

    </header>
    

    
    <div class="article-meta">
      <a href="/blog/2018/08/01/VUEa/" class="article-date">
  <time datetime="2018-08-01T13:01:40.000Z" itemprop="datePublished">2018-08-01</time>
</a>
      
    </div>
    

    

    <div class="article-entry" itemprop="articleBody">
      


      

      
      <h1 id="一、why"><a href="#一、why" class="headerlink" title="一、why?"></a>一、why?</h1><h2 id="（一）性能更好"><a href="#（一）性能更好" class="headerlink" title="（一）性能更好"></a>（一）性能更好</h2><h3 id="1-优点"><a href="#1-优点" class="headerlink" title="1.优点"></a>1.优点</h3><ul>
<li>性能更好</li>
<li>视图、数据分离</li>
<li>维护成本低</li>
</ul>
<h3 id="2-性能"><a href="#2-性能" class="headerlink" title="2.性能"></a>2.性能</h3><ul>
<li>操作 DOM 影响性能，因为操作 DOM 是十分昂贵的</li>
<li>JS 和 DOM 是两种东西，每次连接都需要消耗性能</li>
<li>操作 DOM 会导致重排和重绘</li>
<li>访问 DOM 元素是有代价的，修改 DOM 元素的代价，则更为昂贵，因为它会导致浏览器重新计算页面的机会变化。</li>
</ul>
<h3 id="3-关系"><a href="#3-关系" class="headerlink" title="3.关系"></a>3.关系</h3><ul>
<li>DOM 是一个独立于语言的，用于操作 XML 和 HTML 文档的程序接口(API)。在浏览器中主要用于与 HTML 文档打交道，并且使用 DOM API 用来访问文档中的数据。</li>
<li>DOM 是个与语言无关的 API，它在浏览器中的接口却是用 JavaScript 来实现的。客户端脚本编程大多数都是在和底层文档打交道，DOM 就成为现在 JS 编码中的重要部分。</li>
<li>浏览器中通常会把 DOM 和 javascript 独立实现。</li>
</ul>
<h3 id="4-位置"><a href="#4-位置" class="headerlink" title="4.位置"></a>4.位置</h3><ul>
<li>在 IE 中，JavaScript 的实现名为 JScript，位于 jscript.dll 文件中，DOM 的实现则存在另一个库中，名为 mshtml.dll（内部称为 trident）。</li>
<li>safari 中的 DOM 和渲染是使用 webkit 中的 webcore 实现，JavaScript 部分是由独立的 SquirelFish 引擎来实现。</li>
<li>google chrome 使用 webkit 中的 webCore 库来渲染页面，但 JavaScript 引擎是他们自己研发的，名为 V8。</li>
<li>firefox 的 JavaScript 引擎名为 TraceMonkey，与名为 Gecko 的渲染引擎相互独立。</li>
</ul>
<h3 id="5-渲染过程"><a href="#5-渲染过程" class="headerlink" title="5.渲染过程"></a>5.渲染过程</h3><ul>
<li>浏览器下载完页面中的所有组件：HTML、JavaScript、CSS、图片后，会发生这样的过程：<ul>
<li>解析 HTML，构建 DOM 树 + 解析 CSS，生成 CSS 规则树</li>
<li>合并 DOM 树和 CSS 规则树，生成 render 树</li>
<li>布局 render 树，负责各元素尺寸、位置的计算</li>
<li>绘制 render 树，绘制页面像素信息</li>
<li>浏览器会将各层的信息发送给 GPU，GPU 将各层合成<img src="./render.png"></li>
</ul>
</li>
</ul>
<h3 id="6-重排"><a href="#6-重排" class="headerlink" title="6.重排"></a>6.重排</h3><ul>
<li>当页面布局和几何属性改变时就需要重排：<ul>
<li>添加或删除可见的 DOM 元素。</li>
<li>元素位置改变</li>
<li>元素尺寸改变( 外边距、内边距、边框厚度、宽度、高度等)</li>
<li>内容改变，例：文本改变或图片被另一个不同尺寸的图片替代</li>
<li>页面渲染器初始化</li>
<li>浏览器窗口尺寸改变<br><a target="_blank" rel="noopener" href="https://csstriggers.com/">各 css 属性对重排重绘的影响</a></li>
</ul>
</li>
<li>发生重排的属性：<br>offsetTop、offsetLeft、offsetWidth、offsetHeight<br>scrollTop、scrollLeft、scrollWidth、scrollHeight<br>clientTop、clientLeft、clientWidth、clientHeight<br>getComputedStyle()</li>
</ul>
<h3 id="7-重绘"><a href="#7-重绘" class="headerlink" title="7.重绘"></a>7.重绘</h3><ul>
<li>当页面和元素的颜色相关属性发生变化时会发生重绘。</li>
</ul>
<h3 id="8-虚拟-DOM"><a href="#8-虚拟-DOM" class="headerlink" title="8.虚拟 DOM"></a>8.虚拟 DOM</h3><ul>
<li>vue 的核心是虚拟 dom，使用虚拟 dom 可以减少 dom 的操作，从而提升应用的性能。</li>
<li>在前端的三种语言（html、css、javaScript）中，只有 JS 是一种编程语言，只有 JS 能做到判断、循环、递归、能够实现各种逻辑、实现各种算法。<img src="./html.png">
<img src="./VDOM.png"></li>
</ul>
<h2 id="（二）视图、数据分离"><a href="#（二）视图、数据分离" class="headerlink" title="（二）视图、数据分离"></a>（二）视图、数据分离</h2><h2 id="（三）维护成本低"><a href="#（三）维护成本低" class="headerlink" title="（三）维护成本低"></a>（三）维护成本低</h2><h1 id="二、what？"><a href="#二、what？" class="headerlink" title="二、what？"></a>二、what？</h1><h2 id="（一）渐进式"><a href="#（一）渐进式" class="headerlink" title="（一）渐进式"></a>（一）渐进式</h2><h2 id="（二）MVVM"><a href="#（二）MVVM" class="headerlink" title="（二）MVVM"></a>（二）MVVM</h2><h1 id="三、how"><a href="#三、how" class="headerlink" title="三、how?"></a>三、how?</h1><h2 id="（一）基础-API"><a href="#（一）基础-API" class="headerlink" title="（一）基础 API"></a>（一）基础 API</h2><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;&quot;</span> <span class="attr">app</span>&gt;</span>&#123;&#123; name &#125;&#125;<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="javascript"></span></span><br><span class="line"><span class="javascript">  <span class="keyword">new</span> Vue(&#123;</span></span><br><span class="line"><span class="javascript">    <span class="attr">el</span>: <span class="string">&quot;#app&quot;</span>,</span></span><br><span class="line"><span class="javascript">    <span class="attr">data</span>: &#123;</span></span><br><span class="line"><span class="javascript">      <span class="attr">name</span>: <span class="string">&quot;hello world&quot;</span></span></span><br><span class="line"><span class="javascript">    &#125;</span></span><br><span class="line"><span class="javascript">  &#125;);</span></span><br><span class="line"><span class="javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h3 id="1-模板语法"><a href="#1-模板语法" class="headerlink" title="1.模板语法"></a>1.模板语法</h3><h4 id="（1）文本"><a href="#（1）文本" class="headerlink" title="（1）文本"></a>（1）文本</h4><ul>
<li><p>数据绑定最常见的形式就是使用“Mustache”语法 (双大括号) 的文本插值：无论何时，绑定的数据对象上 msg 属性发生了改变，插值处的内容都会更新。</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span>&gt;</span>&#123;&#123; msg &#125;&#125;<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure></li>
<li><p>通过使用 v-once 指令，你也能执行一次性地插值，当数据改变时，插值处的内容不会更新。但请留心这会影响到该节点上的其它数据绑定：</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">v-once</span>&gt;</span>&#123;&#123; msg &#125;&#125;<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure></li>
<li><p>使用 v-text 指令填充文本</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">v-text</span>=<span class="string">&quot;str&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure></li>
</ul>
<h4 id="（2）html"><a href="#（2）html" class="headerlink" title="（2）html"></a>（2）html</h4><ul>
<li>双大括号会将数据解释为普通文本，而非 HTML 代码。为了输出真正的 HTML，你需要使用 v-html 指令：<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">v-html</span>=<span class="string">&quot;htmlStr&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure></li>
<li>注意，你不能使用 v-html 来复合局部模板，因为 Vue 不是基于字符串的模板引擎。若同时使用，则忽略局部模板。<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">v-html</span>=<span class="string">&quot;htmlStr&quot;</span>&gt;</span>&#123;&#123; msg &#125;&#125;<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure></li>
</ul>
<h4 id="（3）attribute"><a href="#（3）attribute" class="headerlink" title="（3）attribute"></a>（3）attribute</h4><ul>
<li><p>Mustache 语法不能作用在 HTML attribute 上，遇到这种情况应该使用 v-bind 指令：</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">a</span> <span class="attr">v-bind:href</span>=<span class="string">&quot;url&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">a</span> <span class="attr">:href</span>=<span class="string">&quot;url&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br></pre></td></tr></table></figure></li>
<li><p>对于布尔 attribute (它们只要存在就意味着值为 true)，v-bind 工作起来略有不同，如果 isButtonDisabled 的值是 null、undefined 或 false，则 disabled attribute 甚至不会被包含在渲染出来的 &lt;button&gt; 元素中。</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">button</span> <span class="attr">v-bind:disabled</span>=<span class="string">&quot;isButtonDisabled&quot;</span>&gt;</span>Button<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">button</span> <span class="attr">:disabled</span>=<span class="string">&quot;isButtonDisabled&quot;</span>&gt;</span>Button<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br></pre></td></tr></table></figure></li>
</ul>
<h4 id="（4）js-表达式"><a href="#（4）js-表达式" class="headerlink" title="（4）js 表达式"></a>（4）js 表达式</h4><ul>
<li>表达式会在所属 Vue 实例的数据作用域下作为 JavaScript 被解析。有个限制就是，每个绑定都只能包含单个表达式。</li>
</ul>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&#123;&#123; number + 1 &#125;&#125; &#123;&#123; ok ? &#x27;YES&#x27; : &#x27;NO&#x27; &#125;&#125; &#123;&#123;</span><br><span class="line">message.split(&#x27;&#x27;).reverse().join(&#x27;&#x27;)&#125;&#125;</span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">v-bind:id</span>=<span class="string">&quot;&#x27;list-&#x27; + id&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure>

<ul>
<li>模板表达式都被放在沙盒中，只能访问全局变量的一个白名单，如 Math 和 Date 。你不应该在模板表达式中试图访问用户定义的全局变量。</li>
</ul>
<h4 id="（5）事件"><a href="#（5）事件" class="headerlink" title="（5）事件"></a>（5）事件</h4><ul>
<li>Mustache 语法不能作用在 HTML attribute 上，遇到句柄事件应该使用 v-on 指令：<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">v-on:click</span>=<span class="string">&quot;changeEvent&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> @<span class="attr">click</span>=<span class="string">&quot;changeEvent&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure></li>
</ul>
<hr>
<h3 id="2-计算属性与监听器"><a href="#2-计算属性与监听器" class="headerlink" title="2.计算属性与监听器"></a>2.计算属性与监听器</h3><h4 id="（1）methods"><a href="#（1）methods" class="headerlink" title="（1）methods"></a>（1）methods</h4><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;app&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">p</span>&gt;</span></span><br><span class="line">    &#123;&#123;msg()&#125;&#125;</span><br><span class="line">    <span class="tag">&lt;<span class="name">span</span>&gt;</span>&#123;&#123;job&#125;&#125;<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="javascript"></span></span><br><span class="line"><span class="javascript">  <span class="keyword">let</span> vm = <span class="keyword">new</span> Vue(&#123;</span></span><br><span class="line"><span class="javascript">    <span class="attr">el</span>: <span class="string">&quot;#app&quot;</span>,</span></span><br><span class="line"><span class="javascript">    <span class="attr">data</span>: &#123;</span></span><br><span class="line"><span class="javascript">      <span class="attr">name</span>: <span class="string">&quot;小明&quot;</span>,</span></span><br><span class="line"><span class="javascript">      <span class="attr">age</span>: <span class="string">&quot;18岁&quot;</span>,</span></span><br><span class="line"><span class="javascript">      <span class="attr">job</span>: <span class="string">&quot;是一名飞行员&quot;</span></span></span><br><span class="line"><span class="javascript">    &#125;,</span></span><br><span class="line"><span class="javascript">    <span class="attr">methods</span>: &#123;</span></span><br><span class="line"><span class="javascript">      <span class="function"><span class="title">msg</span>(<span class="params"></span>)</span> &#123;</span></span><br><span class="line"><span class="javascript">        <span class="built_in">console</span>.log(<span class="string">`-----methods------`</span>);</span></span><br><span class="line"><span class="javascript">        <span class="keyword">return</span> <span class="built_in">this</span>.name + <span class="built_in">this</span>.age;</span></span><br><span class="line"><span class="javascript">      &#125;</span></span><br><span class="line"><span class="javascript">    &#125;</span></span><br><span class="line"><span class="javascript">  &#125;);</span></span><br><span class="line"><span class="javascript">  vm.job = <span class="string">&quot;是一名教师&quot;</span>;</span></span><br><span class="line"><span class="javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>

<ul>
<li>methods 中定义方法，挂在到 vue 实例上，可以直接访问。</li>
<li>只要页面重新渲染，都会执行一遍所有的方法。</li>
<li>如上，msg 方法并没有依赖 data 的 job 属性，当 job 变化时，msg 方法也会被执行（会输出：—–methods——）；</li>
</ul>
<h4 id="（2）watch"><a href="#（2）watch" class="headerlink" title="（2）watch"></a>（2）watch</h4><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;app&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">p</span>&gt;</span></span><br><span class="line">    &#123;&#123;msg&#125;&#125;</span><br><span class="line">    <span class="tag">&lt;<span class="name">span</span>&gt;</span>&#123;&#123;job&#125;&#125;<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="javascript"></span></span><br><span class="line"><span class="javascript">  <span class="keyword">let</span> vm = <span class="keyword">new</span> Vue(&#123;</span></span><br><span class="line"><span class="javascript">    <span class="attr">el</span>: <span class="string">&quot;#app&quot;</span>,</span></span><br><span class="line"><span class="javascript">    <span class="attr">data</span>: &#123;</span></span><br><span class="line"><span class="javascript">      <span class="attr">name</span>: <span class="string">&quot;小明&quot;</span>,</span></span><br><span class="line"><span class="javascript">      <span class="attr">age</span>: <span class="string">&quot;18岁&quot;</span>,</span></span><br><span class="line"><span class="javascript">      <span class="attr">job</span>: <span class="string">&quot;是一名飞行员&quot;</span>,</span></span><br><span class="line"><span class="javascript">      <span class="attr">msg</span>: <span class="string">&quot;小明18岁&quot;</span></span></span><br><span class="line"><span class="javascript">    &#125;,</span></span><br><span class="line"><span class="javascript">    <span class="attr">watch</span>: &#123;</span></span><br><span class="line"><span class="javascript">      <span class="function"><span class="title">name</span>(<span class="params"></span>)</span> &#123;</span></span><br><span class="line"><span class="javascript">        <span class="built_in">console</span>.log(<span class="string">`-----watch------`</span>);</span></span><br><span class="line"><span class="javascript">        <span class="built_in">this</span>.msg = <span class="built_in">this</span>.name + <span class="built_in">this</span>.age;</span></span><br><span class="line"><span class="javascript">      &#125;,</span></span><br><span class="line"><span class="javascript">      <span class="function"><span class="title">age</span>(<span class="params"></span>)</span> &#123;</span></span><br><span class="line"><span class="javascript">        <span class="built_in">console</span>.log(<span class="string">`-----watch------`</span>);</span></span><br><span class="line"><span class="javascript">        <span class="built_in">this</span>.msg = <span class="built_in">this</span>.name + <span class="built_in">this</span>.age;</span></span><br><span class="line"><span class="javascript">      &#125;</span></span><br><span class="line"><span class="javascript">    &#125;</span></span><br><span class="line"><span class="javascript">  &#125;);</span></span><br><span class="line"><span class="javascript">  vm.job = <span class="string">&quot;是一名教师&quot;</span>;</span></span><br><span class="line"><span class="javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>

<ul>
<li>watch 中监听某个属性变化,并不能直接定义一个新属性。</li>
<li>只有监听的属性变化，才会被执行。</li>
<li>如上，watch 并没有监听 data 的 job 属性，当 job 变化时，不会输出：—–watch——；</li>
</ul>
<h4 id="（3）computed"><a href="#（3）computed" class="headerlink" title="（3）computed"></a>（3）computed</h4><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;app&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">p</span>&gt;</span></span><br><span class="line">    &#123;&#123;msg&#125;&#125;</span><br><span class="line">    <span class="tag">&lt;<span class="name">span</span>&gt;</span>&#123;&#123;job&#125;&#125;<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="javascript"></span></span><br><span class="line"><span class="javascript">  <span class="keyword">let</span> vm = <span class="keyword">new</span> Vue(&#123;</span></span><br><span class="line"><span class="javascript">    <span class="attr">el</span>: <span class="string">&quot;#app&quot;</span>,</span></span><br><span class="line"><span class="javascript">    <span class="attr">data</span>: &#123;</span></span><br><span class="line"><span class="javascript">      <span class="attr">name</span>: <span class="string">&quot;小明&quot;</span>,</span></span><br><span class="line"><span class="javascript">      <span class="attr">age</span>: <span class="string">&quot; 18岁&quot;</span>,</span></span><br><span class="line"><span class="javascript">      <span class="attr">job</span>: <span class="string">&quot; 是一名飞行员&quot;</span></span></span><br><span class="line"><span class="javascript">    &#125;,</span></span><br><span class="line"><span class="javascript">    <span class="attr">computed</span>: &#123;</span></span><br><span class="line"><span class="javascript">      <span class="attr">msg</span>: &#123;</span></span><br><span class="line"><span class="javascript">        <span class="function"><span class="title">get</span>(<span class="params"></span>)</span> &#123;</span></span><br><span class="line"><span class="javascript">          <span class="built_in">console</span>.log(<span class="string">&quot;-----computed-------&quot;</span>);</span></span><br><span class="line"><span class="javascript">          <span class="keyword">return</span> <span class="built_in">this</span>.name + <span class="built_in">this</span>.age;</span></span><br><span class="line"><span class="javascript">        &#125;,</span></span><br><span class="line"><span class="javascript">        <span class="function"><span class="title">set</span>(<span class="params">value</span>)</span> &#123;</span></span><br><span class="line"><span class="javascript">          <span class="built_in">console</span>.log(<span class="string">&quot;-----computed-------&quot;</span>);</span></span><br><span class="line"><span class="javascript">          <span class="keyword">let</span> arr = value.split(<span class="string">&quot; &quot;</span>);</span></span><br><span class="line"><span class="javascript">          <span class="built_in">this</span>.name = arr[<span class="number">0</span>];</span></span><br><span class="line"><span class="javascript">          <span class="built_in">this</span>.age = arr[<span class="number">1</span>];</span></span><br><span class="line"><span class="javascript">        &#125;</span></span><br><span class="line"><span class="javascript">      &#125;</span></span><br><span class="line"><span class="javascript">    &#125;</span></span><br><span class="line"><span class="javascript">  &#125;);</span></span><br><span class="line"><span class="javascript">  vm.job = <span class="string">&quot;是一名教师&quot;</span>;</span></span><br><span class="line"><span class="javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>

<ul>
<li>computed 中定义某个属性为计算属性, 也可直接定义一个新属性。</li>
<li>只有依赖的属性变化，才会被执行。</li>
<li>如上，computed 中 msg 并没有依赖 data 的 job 属性，当 job 变化时，不会输出：—–computed——；</li>
</ul>
<hr>
<h3 id="3-类与样式"><a href="#3-类与样式" class="headerlink" title="3.类与样式"></a>3.类与样式</h3><h4 id="（1）class"><a href="#（1）class" class="headerlink" title="（1）class"></a>（1）class</h4><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE <span class="meta-keyword">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">&quot;en&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">&quot;UTF-8&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">name</span>=<span class="string">&quot;viewport&quot;</span> <span class="attr">content</span>=<span class="string">&quot;width=device-width, initial-scale=1.0&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">http-equiv</span>=<span class="string">&quot;X-UA-Compatible&quot;</span> <span class="attr">content</span>=<span class="string">&quot;ie=edge&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>app<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">style</span>&gt;</span><span class="css"></span></span><br><span class="line"><span class="css">      <span class="selector-id">#app</span> <span class="selector-tag">div</span> &#123;</span></span><br><span class="line"><span class="css">        <span class="attribute">width</span>: <span class="number">100px</span>;</span></span><br><span class="line"><span class="css">        <span class="attribute">height</span>: <span class="number">100px</span>;</span></span><br><span class="line"><span class="css">        <span class="attribute">text-align</span>: center;</span></span><br><span class="line"><span class="css">        <span class="attribute">background-color</span>: pink;</span></span><br><span class="line"><span class="css">        <span class="attribute">line-height</span>: <span class="number">100px</span>;</span></span><br><span class="line"><span class="css">        <span class="attribute">margin-top</span>: <span class="number">20px</span>;</span></span><br><span class="line"><span class="css">      &#125;</span></span><br><span class="line"><span class="css">      <span class="selector-class">.red</span> &#123;</span></span><br><span class="line"><span class="css">        <span class="attribute">background-color</span>: red <span class="meta">!important</span>;</span></span><br><span class="line"><span class="css">      &#125;</span></span><br><span class="line"><span class="css">      <span class="selector-class">.border</span> &#123;</span></span><br><span class="line"><span class="css">        <span class="attribute">border</span>: <span class="number">5px</span> solid;</span></span><br><span class="line"><span class="css">        <span class="attribute">box-sizing</span>: border-box;</span></span><br><span class="line"><span class="css">      &#125;</span></span><br><span class="line"><span class="css">    </span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;app&quot;</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">div</span> <span class="attr">:class</span>=<span class="string">&quot;className&quot;</span> @<span class="attr">click</span>=<span class="string">&quot;changeBg1&quot;</span>&gt;</span>1<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">div</span> <span class="attr">:class</span>=<span class="string">&quot;[className1, className2]&quot;</span> @<span class="attr">click</span>=<span class="string">&quot;changeBg2&quot;</span>&gt;</span>2<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">div</span> <span class="attr">:class</span>=<span class="string">&quot;&#123;&#x27;red&#x27;: isRed&#125;&quot;</span> @<span class="attr">click</span>=<span class="string">&quot;changeBg3&quot;</span>&gt;</span>3<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="javascript"></span></span><br><span class="line"><span class="javascript">      <span class="keyword">let</span> vm = <span class="keyword">new</span> Vue(&#123;</span></span><br><span class="line"><span class="javascript">        <span class="attr">el</span>: <span class="string">&quot;#app&quot;</span>,</span></span><br><span class="line"><span class="javascript">        <span class="attr">data</span>: &#123;</span></span><br><span class="line"><span class="javascript">          <span class="attr">msg</span>: <span class="string">&quot;小明&quot;</span>,</span></span><br><span class="line"><span class="javascript">          <span class="attr">className</span>: <span class="string">&quot;&quot;</span>,</span></span><br><span class="line"><span class="javascript">          <span class="attr">className1</span>: <span class="string">&quot;&quot;</span>,</span></span><br><span class="line"><span class="javascript">          <span class="attr">className2</span>: <span class="string">&quot;border&quot;</span>,</span></span><br><span class="line"><span class="javascript">          <span class="attr">isRed</span>: <span class="literal">false</span></span></span><br><span class="line"><span class="javascript">        &#125;,</span></span><br><span class="line"><span class="javascript">        <span class="attr">methods</span>: &#123;</span></span><br><span class="line"><span class="javascript">          <span class="function"><span class="title">changeBg1</span>(<span class="params"></span>)</span> &#123;</span></span><br><span class="line"><span class="javascript">            <span class="built_in">this</span>.className = <span class="built_in">this</span>.className === <span class="string">&quot;&quot;</span> ? <span class="string">&quot;red&quot;</span> : <span class="string">&quot;&quot;</span>;</span></span><br><span class="line"><span class="javascript">          &#125;,</span></span><br><span class="line"><span class="javascript">          <span class="function"><span class="title">changeBg2</span>(<span class="params"></span>)</span> &#123;</span></span><br><span class="line"><span class="javascript">            <span class="built_in">this</span>.className1 = <span class="built_in">this</span>.className1 === <span class="string">&quot;&quot;</span> ? <span class="string">&quot;red&quot;</span> : <span class="string">&quot;&quot;</span>;</span></span><br><span class="line"><span class="javascript">          &#125;,</span></span><br><span class="line"><span class="javascript">          <span class="function"><span class="title">changeBg3</span>(<span class="params"></span>)</span> &#123;</span></span><br><span class="line"><span class="javascript">            <span class="built_in">this</span>.isRed = !<span class="built_in">this</span>.isRed;</span></span><br><span class="line"><span class="javascript">          &#125;</span></span><br><span class="line"><span class="javascript">        &#125;</span></span><br><span class="line"><span class="javascript">      &#125;);</span></span><br><span class="line"><span class="javascript">    </span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure>

<ul>
<li>使用变量 className, 变量的值会被应用为 class 的属性值</li>
<li>当使用多个类名的时候，可以使用数组（classList）, 每一项的值会被应用为 class 的属性值</li>
<li>可以使用对象，动态的控制类名是否被应用, 键值对中的 key 对应 className，value 的 boolean 值决定当前类名是否应用</li>
</ul>
<h4 id="（2）style"><a href="#（2）style" class="headerlink" title="（2）style"></a>（2）style</h4><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE <span class="meta-keyword">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">&quot;en&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">&quot;UTF-8&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">name</span>=<span class="string">&quot;viewport&quot;</span> <span class="attr">content</span>=<span class="string">&quot;width=device-width, initial-scale=1.0&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">http-equiv</span>=<span class="string">&quot;X-UA-Compatible&quot;</span> <span class="attr">content</span>=<span class="string">&quot;ie=edge&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>app<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">style</span>&gt;</span><span class="css"></span></span><br><span class="line"><span class="css">      <span class="selector-id">#app</span> <span class="selector-tag">div</span> &#123;</span></span><br><span class="line"><span class="css">        <span class="attribute">width</span>: <span class="number">100px</span>;</span></span><br><span class="line"><span class="css">        <span class="attribute">height</span>: <span class="number">100px</span>;</span></span><br><span class="line"><span class="css">        <span class="attribute">text-align</span>: center;</span></span><br><span class="line"><span class="css">        <span class="attribute">background-color</span>: pink;</span></span><br><span class="line"><span class="css">        <span class="attribute">line-height</span>: <span class="number">100px</span>;</span></span><br><span class="line"><span class="css">        <span class="attribute">margin-top</span>: <span class="number">20px</span>;</span></span><br><span class="line"><span class="css">      &#125;</span></span><br><span class="line"><span class="css">    </span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;app&quot;</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">div</span> <span class="attr">:style</span>=<span class="string">&quot;style&quot;</span>&gt;</span>1<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">div</span> <span class="attr">:style</span>=<span class="string">&quot;[style1, style2]&quot;</span>&gt;</span>2<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">div</span> <span class="attr">:style</span>=<span class="string">&quot;&#123;color: color&#125;&quot;</span>&gt;</span>3<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="javascript"></span></span><br><span class="line"><span class="javascript">      <span class="keyword">let</span> vm = <span class="keyword">new</span> Vue(&#123;</span></span><br><span class="line"><span class="javascript">        <span class="attr">el</span>: <span class="string">&quot;#app&quot;</span>,</span></span><br><span class="line"><span class="javascript">        <span class="attr">data</span>: &#123;</span></span><br><span class="line"><span class="javascript">          <span class="attr">style</span>: &#123;</span></span><br><span class="line"><span class="javascript">            <span class="attr">fontSize</span>: <span class="string">&quot;30px&quot;</span></span></span><br><span class="line"><span class="javascript">          &#125;,</span></span><br><span class="line"><span class="javascript">          <span class="attr">style1</span>: &#123;</span></span><br><span class="line"><span class="javascript">            <span class="attr">fontSize</span>: <span class="string">&quot;20px&quot;</span>,</span></span><br><span class="line"><span class="javascript">            <span class="attr">fontStyle</span>: <span class="string">&quot;bolder&quot;</span>,</span></span><br><span class="line"><span class="javascript">            <span class="attr">color</span>: <span class="string">&quot;#fff&quot;</span></span></span><br><span class="line"><span class="javascript">          &#125;,</span></span><br><span class="line"><span class="javascript">          <span class="attr">style2</span>: &#123;</span></span><br><span class="line"><span class="javascript">            <span class="attr">backgroundColor</span>: <span class="string">&quot;blue&quot;</span></span></span><br><span class="line"><span class="javascript">          &#125;,</span></span><br><span class="line"><span class="javascript">          <span class="attr">color</span>: <span class="string">&quot;red&quot;</span></span></span><br><span class="line"><span class="javascript">        &#125;</span></span><br><span class="line"><span class="javascript">      &#125;);</span></span><br><span class="line"><span class="javascript">    </span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure>

<ul>
<li>可以应用为一个对象，键值对中的 key 对应样式属性，value 对应样式属性值</li>
<li>当应用多个对象时，通过数组将对象集中起来</li>
</ul>
<hr>
<h3 id="4-条件渲染"><a href="#4-条件渲染" class="headerlink" title="4.条件渲染"></a>4.条件渲染</h3><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;app&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">ul</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">li</span> <span class="attr">v-if</span>=<span class="string">&quot;show === 1&quot;</span>&gt;</span>中国70周年庆典1<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">li</span> <span class="attr">v-else-if</span>=<span class="string">&quot;show === 2&quot;</span>&gt;</span>中国70周年庆典2<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">li</span> <span class="attr">v-else-if</span>=<span class="string">&quot;show === 3&quot;</span>&gt;</span>中国70周年庆典3<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">li</span> <span class="attr">v-else-if</span>=<span class="string">&quot;show === 4&quot;</span>&gt;</span>中国70周年庆典4<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">li</span> <span class="attr">v-else</span>&gt;</span>中国70周年庆典5<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">ul</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">button</span> @<span class="attr">click</span>=<span class="string">&quot;change&quot;</span>&gt;</span>增加<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="javascript"></span></span><br><span class="line"><span class="javascript">  <span class="keyword">let</span> vm = <span class="keyword">new</span> Vue(&#123;</span></span><br><span class="line"><span class="javascript">    <span class="attr">el</span>: <span class="string">&quot;#app&quot;</span>,</span></span><br><span class="line"><span class="javascript">    <span class="attr">data</span>: &#123;</span></span><br><span class="line"><span class="javascript">      <span class="attr">show</span>: <span class="number">1</span></span></span><br><span class="line"><span class="javascript">    &#125;,</span></span><br><span class="line"><span class="javascript">    <span class="attr">methods</span>: &#123;</span></span><br><span class="line"><span class="javascript">      <span class="function"><span class="title">change</span>(<span class="params"></span>)</span> &#123;</span></span><br><span class="line"><span class="javascript">        <span class="built_in">this</span>.show++;</span></span><br><span class="line"><span class="javascript">        <span class="built_in">console</span>.log(<span class="built_in">this</span>.show);</span></span><br><span class="line"><span class="javascript">      &#125;</span></span><br><span class="line"><span class="javascript">    &#125;</span></span><br><span class="line"><span class="javascript">  &#125;);</span></span><br><span class="line"><span class="javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h4 id="（1）v-if"><a href="#（1）v-if" class="headerlink" title="（1）v-if"></a>（1）v-if</h4><ul>
<li>当 v-if 的属性值为 true 时，当前元素才会被渲染</li>
<li>若 v-if 的属性值为 false，当前元素会被直接移除</li>
</ul>
<h4 id="（2）v-else-if"><a href="#（2）v-else-if" class="headerlink" title="（2）v-else-if"></a>（2）v-else-if</h4><ul>
<li>当 v-else-if 的属性值为 true 时，当前元素才会被渲染</li>
<li>若 v-else-if 的属性值为 false，当前元素会被直接移除</li>
</ul>
<h4 id="（3）v-else"><a href="#（3）v-else" class="headerlink" title="（3）v-else"></a>（3）v-else</h4><ul>
<li>与 v-if、v-else-if 配合使用</li>
<li><font color=red>中间不能出现第三者，配合使用的元素必须是相连的兄弟元素</font></li>
</ul>
<h4 id="（4）v-show"><a href="#（4）v-show" class="headerlink" title="（4）v-show"></a>（4）v-show</h4><ul>
<li>当 v-show 的属性值为 true 时，当前元素才会显示</li>
<li>若 v-show 的属性值为 false，当前元素会添加 display: none 行间样式</li>
</ul>
<h4 id="（5）dom-复用"><a href="#（5）dom-复用" class="headerlink" title="（5）dom 复用"></a>（5）dom 复用</h4><ul>
<li>vue 会自动的复用页面已经存在的 dom</li>
<li>通过定义不一样的 key 属性来取消复用</li>
</ul>
<hr>
<h3 id="5-列表渲染"><a href="#5-列表渲染" class="headerlink" title="5.列表渲染"></a>5.列表渲染</h3><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE <span class="meta-keyword">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">&quot;en&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">&quot;UTF-8&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">name</span>=<span class="string">&quot;viewport&quot;</span> <span class="attr">content</span>=<span class="string">&quot;width=device-width, initial-scale=1.0&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">http-equiv</span>=<span class="string">&quot;X-UA-Compatible&quot;</span> <span class="attr">content</span>=<span class="string">&quot;ie=edge&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>app<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">style</span>&gt;</span><span class="css"></span></span><br><span class="line"><span class="css">      <span class="selector-tag">ul</span> &#123;</span></span><br><span class="line"><span class="css">        <span class="attribute">width</span>: <span class="number">300px</span>;</span></span><br><span class="line"><span class="css">      &#125;</span></span><br><span class="line"><span class="css">      <span class="selector-tag">ul</span> <span class="selector-tag">li</span> &#123;</span></span><br><span class="line"><span class="css">        <span class="attribute">margin-bottom</span>: <span class="number">20px</span>;</span></span><br><span class="line"><span class="css">      &#125;</span></span><br><span class="line"><span class="css">      <span class="selector-tag">ul</span> <span class="selector-tag">li</span> <span class="selector-tag">span</span><span class="selector-class">.new</span> &#123;</span></span><br><span class="line"><span class="css">        <span class="attribute">background-color</span>: red;</span></span><br><span class="line"><span class="css">        <span class="attribute">color</span>: <span class="number">#fff</span>;</span></span><br><span class="line"><span class="css">      &#125;</span></span><br><span class="line"><span class="css">    </span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;app&quot;</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">ul</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">li</span> <span class="attr">v-for</span>=<span class="string">&quot;item in list&quot;</span> <span class="attr">:key</span>=<span class="string">&quot;item.id&quot;</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;<span class="name">span</span>&gt;</span>&#123;&#123;item.title&#125;&#125;<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;<span class="name">span</span> <span class="attr">class</span>=<span class="string">&quot;new&quot;</span> <span class="attr">v-show</span>=<span class="string">&quot;item.new&quot;</span>&gt;</span>新<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">ul</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="javascript"></span></span><br><span class="line"><span class="javascript">      <span class="keyword">let</span> vm = <span class="keyword">new</span> Vue(&#123;</span></span><br><span class="line"><span class="javascript">        <span class="attr">el</span>: <span class="string">&quot;#app&quot;</span>,</span></span><br><span class="line"><span class="javascript">        <span class="attr">data</span>: &#123;</span></span><br><span class="line"><span class="javascript">          <span class="attr">list</span>: [</span></span><br><span class="line"><span class="javascript">            &#123;</span></span><br><span class="line"><span class="javascript">              <span class="attr">title</span>: <span class="string">&quot;中国70周年庆典&quot;</span>,</span></span><br><span class="line"><span class="javascript">              <span class="attr">new</span>: <span class="literal">false</span>,</span></span><br><span class="line"><span class="javascript">              <span class="attr">id</span>: <span class="number">0</span></span></span><br><span class="line"><span class="javascript">            &#125;,</span></span><br><span class="line"><span class="javascript">            &#123;</span></span><br><span class="line"><span class="javascript">              <span class="attr">title</span>: <span class="string">&quot;新型冠状病毒&quot;</span>,</span></span><br><span class="line"><span class="javascript">              <span class="attr">new</span>: <span class="literal">true</span>,</span></span><br><span class="line"><span class="javascript">              <span class="attr">id</span>: <span class="number">1</span></span></span><br><span class="line"><span class="javascript">            &#125;,</span></span><br><span class="line"><span class="javascript">            &#123;</span></span><br><span class="line"><span class="javascript">              <span class="attr">title</span>: <span class="string">&quot;NBA巨星科比坠机身亡&quot;</span>,</span></span><br><span class="line"><span class="javascript">              <span class="attr">new</span>: <span class="literal">true</span>,</span></span><br><span class="line"><span class="javascript">              <span class="attr">id</span>: <span class="number">2</span></span></span><br><span class="line"><span class="javascript">            &#125;,</span></span><br><span class="line"><span class="javascript">            &#123;</span></span><br><span class="line"><span class="javascript">              <span class="attr">title</span>: <span class="string">&quot;澳大利亚大火&quot;</span>,</span></span><br><span class="line"><span class="javascript">              <span class="attr">new</span>: <span class="literal">false</span>,</span></span><br><span class="line"><span class="javascript">              <span class="attr">id</span>: <span class="number">3</span></span></span><br><span class="line"><span class="javascript">            &#125;,</span></span><br><span class="line"><span class="javascript">            &#123;</span></span><br><span class="line"><span class="javascript">              <span class="attr">title</span>: <span class="string">&quot;2020鼠年春晚&quot;</span>,</span></span><br><span class="line"><span class="javascript">              <span class="attr">new</span>: <span class="literal">false</span>,</span></span><br><span class="line"><span class="javascript">              <span class="attr">id</span>: <span class="number">4</span></span></span><br><span class="line"><span class="javascript">            &#125;</span></span><br><span class="line"><span class="javascript">          ]</span></span><br><span class="line"><span class="javascript">        &#125;</span></span><br><span class="line"><span class="javascript">      &#125;);</span></span><br><span class="line"><span class="javascript">    </span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h4 id="（1）v-for"><a href="#（1）v-for" class="headerlink" title="（1）v-for"></a>（1）v-for</h4><ul>
<li>v-for 属性值可以是一个数组（listArr）</li>
<li>子元素使用的每一项 item 需要手动在 v-for 中定义（item in listArr）</li>
<li>v-for 属性值也可以是一个对象（listObj）</li>
<li>子元素使用的数据（键、值、索引）需要手动在 v-for 中定义（(key, value, index) in listObj）</li>
<li>建议使用 v-bind:key 定义一个唯一的值，复用 dom 提高效率（:key=item.id）</li>
</ul>
<h4 id="（2）数组更新检测"><a href="#（2）数组更新检测" class="headerlink" title="（2）数组更新检测"></a>（2）数组更新检测</h4><ul>
<li><font color=red>在数据数组中利用索引手动增减数据，视图不会更新</font></li>
<li><font color=red>改变数据数组的引用，视图会更新</font></li>
<li><font color=red>Vue 将被侦听的数组的变异方法进行了包裹，所以它们也将会触发视图更新</font></li>
<li>数组变异方法：<ul>
<li>push()</li>
<li>pop()</li>
<li>shift()</li>
<li>unshift()</li>
<li>splice()</li>
<li>sort()</li>
<li>reverse()</li>
</ul>
</li>
</ul>
<h4 id="（3）对象检测更新"><a href="#（3）对象检测更新" class="headerlink" title="（3）对象检测更新"></a>（3）对象检测更新</h4><ul>
<li><font color=red>在数据对象中利用引用手动增减属性，视图不会更新</font></li>
<li><font color=red>改变数据对象的引用，视图会更新</font></li>
<li><font color=red>使用 Vue.set(obj, prop, data)，视图会更新</font></li>
</ul>
<h4 id="（4）模板-template"><a href="#（4）模板-template" class="headerlink" title="（4）模板 template"></a>（4）模板 template</h4><ul>
<li>列表渲染可以使用 template 模板作为某些元素的父元素进行嵌套方便循环</li>
<li>当循环结束，template 不会存在视图结构中</li>
</ul>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">template</span> <span class="attr">v-for</span>=<span class="string">&quot;item in list&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">div</span>&gt;</span>&#123;&#123;item.content&#125;&#125;<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">template</span>&gt;</span></span><br></pre></td></tr></table></figure>

<hr>
<h3 id="6-双向数据绑定"><a href="#6-双向数据绑定" class="headerlink" title="6.双向数据绑定"></a>6.双向数据绑定</h3><h4 id="（1）v-model"><a href="#（1）v-model" class="headerlink" title="（1）v-model"></a>（1）v-model</h4><ul>
<li>你可以用 v-model 指令在表单 &lt;input&gt;、&lt;textarea&gt; 及 &lt;select&gt; 元素上创建双向数据绑定。</li>
<li>v-model 在内部为不同的输入元素使用不同的属性并抛出不同的事件：<ul>
<li>text 和 textarea 元素使用 value 属性和 input 事件；</li>
<li>checkbox 和 radio 使用 checked 属性和 change 事件；</li>
<li>select 字段将 value 作为 prop 并将 change 作为事件。</li>
</ul>
</li>
<li><font color=red>在文本区域插值 (&lt;textarea&gt;</textarea>) 并不会生效，应用 v-model 来代替。</font></li>
<li>单个复选框，绑定到布尔值：多个复选框，绑定到同一个数组：</li>
<li>如果 v-model 表达式的初始值未能匹配任何选项，&lt;select&gt; 元素将被渲染为“未选中”状态。</li>
</ul>
<h4 id="（2）修饰符"><a href="#（2）修饰符" class="headerlink" title="（2）修饰符"></a>（2）修饰符</h4><ul>
<li>在默认情况下，v-model 在每次 input 事件触发后将输入框的值与数据进行同步 (除了上述输入法组合文字时)。你可以添加 lazy 修饰符，从而转变为使用 change 事件进行同步：</li>
<li>如果想自动将用户的输入值转为数值类型，可以给 v-model 添加 number 修饰符：在 type=”number” 时，HTML 输入元素的值也总会返回字符串。如果这个值无法被 parseFloat() 解析，则会返回原始的值。</li>
<li>如果要自动过滤用户输入的首尾空白字符，可以给 v-model 添加 trim 修饰符：</li>
</ul>
<hr>
<h3 id="7-事件处理"><a href="#7-事件处理" class="headerlink" title="7.事件处理"></a>7.事件处理</h3><h4 id="（1）监听"><a href="#（1）监听" class="headerlink" title="（1）监听"></a>（1）监听</h4><ul>
<li>可以用 v-on 指令监听 DOM 事件，并在触发时运行一些 JavaScript 代码。</li>
<li>然而许多事件处理逻辑会更为复杂，所以直接把 JavaScript 代码写在 v-on 指令中是不可行的。因此 v-on 还可以接收一个需要调用的方法名称。</li>
<li>除了直接绑定到一个方法，也可以在内联 JavaScript 语句中调用方法并且传参。</li>
</ul>
<h4 id="（2）修饰符-1"><a href="#（2）修饰符-1" class="headerlink" title="（2）修饰符"></a>（2）修饰符</h4><ul>
<li>Vue.js 为 v-on 提供了事件修饰符。之前提过，修饰符是由点开头的指令后缀来表示的。<ul>
<li>.stop 阻止冒泡</li>
<li>.prevent 阻止默认事件</li>
<li>.capture 捕获模式</li>
<li>.self 自身事件源</li>
<li>.once 执行一次</li>
<li>.passive 不阻止默认事件</li>
</ul>
</li>
</ul>
<h4 id="（3）按键修饰符"><a href="#（3）按键修饰符" class="headerlink" title="（3）按键修饰符"></a>（3）按键修饰符</h4><ul>
<li><p>你可以直接将 KeyboardEvent.key 暴露的任意有效按键名转换为 kebab-case 来作为修饰符。</p>
<blockquote>
<p>&lt;input v-on:keyup.page-down=”onPageDown”&gt;</p>
</blockquote>
</li>
<li><p>使用 keyCode attribute 也是允许的：</p>
<blockquote>
<p>&lt;input v-on:keyup.13=”submit”&gt;</p>
</blockquote>
</li>
<li><p>为了在必要的情况下支持旧浏览器，Vue 提供了绝大多数常用的按键码的别名：</p>
<ul>
<li>.enter</li>
<li>.tab</li>
<li>.delete (捕获“删除”和“退格”键)</li>
<li>.esc</li>
<li>.space</li>
<li>.up</li>
<li>.down</li>
<li>.left</li>
<li>.right</li>
</ul>
</li>
<li><p>你还可以通过全局 config.keyCodes 对象自定义按键修饰符别名：</p>
<blockquote>
<p>可以使用 v-on:keyup.f1 Vue.config.keyCodes.f1 = 112</p>
</blockquote>
</li>
</ul>
<h4 id="（4）系统修饰键"><a href="#（4）系统修饰键" class="headerlink" title="（4）系统修饰键"></a>（4）系统修饰键</h4><ul>
<li>可以用如下修饰符来实现仅在按下相应按键时才触发鼠标或键盘事件的监听器。<ul>
<li>.ctrl</li>
<li>.alt</li>
<li>.shift</li>
<li>.meta</li>
<li>.exact 修饰符允许你控制由精确的系统修饰符组合触发的事件。</li>
</ul>
</li>
</ul>
<h4 id="（5）鼠标修饰符"><a href="#（5）鼠标修饰符" class="headerlink" title="（5）鼠标修饰符"></a>（5）鼠标修饰符</h4><ul>
<li>鼠标按钮修饰符<ul>
<li>.left</li>
<li>.right</li>
<li>.middle</li>
</ul>
</li>
</ul>
<hr>
<h2 id="（二）组件"><a href="#（二）组件" class="headerlink" title="（二）组件"></a>（二）组件</h2><h3 id="1-注册组件"><a href="#1-注册组件" class="headerlink" title="1.注册组件"></a>1.注册组件</h3><h4 id="（1）全局组件"><a href="#（1）全局组件" class="headerlink" title="（1）全局组件"></a>（1）全局组件</h4><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">tag-name</span> <span class="attr">:prop-name</span>=<span class="string">&quot;data&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">tag-name</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="javascript"></span></span><br><span class="line"><span class="javascript">  Vue.component(<span class="string">&quot;tagName&quot;</span>, &#123;</span></span><br><span class="line"><span class="javascript">    <span class="attr">props</span>: [<span class="string">&quot;propName&quot;</span>],</span></span><br><span class="line"><span class="javascript">    <span class="attr">template</span>: <span class="string">&quot;&lt;html&gt;&#123;&#123;propName&#125;&#125;&lt;/html&gt;&quot;</span>,</span></span><br><span class="line"><span class="javascript">    <span class="function"><span class="title">data</span>(<span class="params"></span>)</span> &#123;</span></span><br><span class="line"><span class="javascript">      <span class="keyword">return</span> &#123;&#125;;</span></span><br><span class="line"><span class="javascript">    &#125;,</span></span><br><span class="line"><span class="javascript">    <span class="attr">methods</span>: &#123;</span></span><br><span class="line"><span class="javascript">      <span class="function"><span class="title">getData</span>(<span class="params"></span>)</span> &#123;&#125;</span></span><br><span class="line"><span class="javascript">    &#125;</span></span><br><span class="line"><span class="javascript">  &#125;);</span></span><br><span class="line"><span class="javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>

<ul>
<li>当使用 kebab-case (短横线分隔命名) 定义一个组件时，你也必须在引用这个自定义元素时使用 kebab-case，例如 &lt;my-component-name&gt;。</li>
</ul>
<h4 id="（2）局部组件"><a href="#（2）局部组件" class="headerlink" title="（2）局部组件"></a>（2）局部组件</h4><ul>
<li>全局注册往往是不够理想的。比如，如果你使用一个像 webpack 这样的构建系统，全局注册所有的组件意味着即便你已经不再使用一个组件了，它仍然会被包含在你最终的构建结果中。这造成了用户下载的 JavaScript 的无谓的增加。</li>
</ul>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">tag-name</span> <span class="attr">:prop-name</span>=<span class="string">&quot;data&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">tag-name</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="javascript"></span></span><br><span class="line"><span class="javascript">  <span class="keyword">new</span> Vue(&#123;</span></span><br><span class="line"><span class="javascript">    <span class="attr">el</span>: <span class="string">&quot;#app&quot;</span>,</span></span><br><span class="line"><span class="javascript">    <span class="attr">components</span>: &#123;</span></span><br><span class="line"><span class="javascript">      <span class="attr">tagName</span>: &#123;</span></span><br><span class="line"><span class="javascript">        <span class="attr">props</span>: [<span class="string">&quot;propName&quot;</span>],</span></span><br><span class="line"><span class="javascript">        <span class="attr">template</span>: <span class="string">&quot;&lt;html&gt;&#123;&#123;propName&#125;&#125;&lt;/html&gt;&quot;</span>,</span></span><br><span class="line"><span class="javascript">        <span class="function"><span class="title">data</span>(<span class="params"></span>)</span> &#123;</span></span><br><span class="line"><span class="javascript">          <span class="keyword">return</span> &#123;&#125;;</span></span><br><span class="line"><span class="javascript">        &#125;,</span></span><br><span class="line"><span class="javascript">        <span class="attr">methods</span>: &#123;</span></span><br><span class="line"><span class="javascript">          <span class="function"><span class="title">getData</span>(<span class="params"></span>)</span> &#123;&#125;</span></span><br><span class="line"><span class="javascript">        &#125;</span></span><br><span class="line"><span class="javascript">      &#125;</span></span><br><span class="line"><span class="javascript">    &#125;</span></span><br><span class="line"><span class="javascript">  &#125;);</span></span><br><span class="line"><span class="javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>

<hr>
<h4 id="（3）特别注意"><a href="#（3）特别注意" class="headerlink" title="（3）特别注意"></a>（3）特别注意</h4><ul>
<li>取而代之的是，一个组件的 data 选项必须是一个函数，因此每个实例可以维护一份被返回对象的独立的拷贝：</li>
<li>every component must have a single root element (每个组件必须只有一个根元素)。你可以将模板的内容包裹在一个父元素内，来修复这个问题；</li>
<li>当一个值传递给一个 prop attribute 的时候，它就变成了那个组件实例的一个属性。为了给博文组件传递一个标题，我们可以用一个 props 选项将其包含在该组件可接受的 prop 列表中：</li>
</ul>
<h3 id="2-数据传递"><a href="#2-数据传递" class="headerlink" title="2.数据传递"></a>2.数据传递</h3><h4 id="（1）父传子"><a href="#（1）父传子" class="headerlink" title="（1）父传子"></a>（1）父传子</h4><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;app&quot;</span>&gt;</span></span><br><span class="line">  <span class="comment">&lt;!-- 静态传递， 组件显示内容为 val --&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">my-component</span> <span class="attr">content</span>=<span class="string">&quot;val&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">my-component</span>&gt;</span></span><br><span class="line">  <span class="comment">&lt;!-- 动态传递，组件显示内容为 hello world!!! --&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">my-component</span> <span class="attr">:content</span>=<span class="string">&quot;val&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">my-component</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="javascript"></span></span><br><span class="line"><span class="javascript">  <span class="keyword">let</span> vm = <span class="keyword">new</span> Vue(&#123;</span></span><br><span class="line"><span class="javascript">    <span class="attr">el</span>: <span class="string">&quot;#app&quot;</span>,</span></span><br><span class="line"><span class="javascript">    <span class="attr">data</span>: &#123;</span></span><br><span class="line"><span class="javascript">      <span class="attr">val</span>: <span class="string">&quot;hello world!!!&quot;</span></span></span><br><span class="line"><span class="javascript">    &#125;,</span></span><br><span class="line"><span class="javascript">    <span class="attr">components</span>: &#123;</span></span><br><span class="line"><span class="javascript">      <span class="attr">myComponent</span>: &#123;</span></span><br><span class="line"><span class="javascript">        <span class="attr">props</span>: [<span class="string">&quot;content&quot;</span>],</span></span><br><span class="line"><span class="javascript">        <span class="attr">template</span>: <span class="string">`&lt;div&gt;&#123;&#123;content&#125;&#125;&lt;/div&gt;`</span></span></span><br><span class="line"><span class="javascript">      &#125;</span></span><br><span class="line"><span class="javascript">    &#125;</span></span><br><span class="line"><span class="javascript">  &#125;);</span></span><br><span class="line"><span class="javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>

<ul>
<li>在父组件上通过自定义属性进行传值，属性名为接收的变量名，属性值为传递的数据</li>
<li>在子组件中通过 props 属性的值来对应接收的数据</li>
</ul>
<h4 id="（2）子传父"><a href="#（2）子传父" class="headerlink" title="（2）子传父"></a>（2）子传父</h4><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;app&quot;</span>&gt;</span></span><br><span class="line">  <span class="comment">&lt;!-- 静态传递， 组件显示内容为 val --&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">my-component</span> <span class="attr">content</span>=<span class="string">&quot;val&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">my-component</span>&gt;</span></span><br><span class="line">  <span class="comment">&lt;!-- 动态传递，组件显示内容为 hello world!!! --&gt;</span></span><br><span class="line">  <span class="comment">&lt;!-- 监听自定义事件transfer，并由getData事件处理程序处理 --&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">my-component</span> <span class="attr">:content</span>=<span class="string">&quot;val&quot;</span> @<span class="attr">transfer</span>=<span class="string">&quot;getData&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">my-component</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="javascript"></span></span><br><span class="line"><span class="javascript">  <span class="keyword">let</span> vm = <span class="keyword">new</span> Vue(&#123;</span></span><br><span class="line"><span class="javascript">    <span class="attr">el</span>: <span class="string">&quot;#app&quot;</span>,</span></span><br><span class="line"><span class="javascript">    <span class="attr">data</span>: &#123;</span></span><br><span class="line"><span class="javascript">      <span class="attr">val</span>: <span class="string">&quot;hello world!!!&quot;</span></span></span><br><span class="line"><span class="javascript">    &#125;,</span></span><br><span class="line"><span class="javascript">    <span class="attr">components</span>: &#123;</span></span><br><span class="line"><span class="javascript">      <span class="attr">myComponent</span>: &#123;</span></span><br><span class="line"><span class="javascript">        <span class="attr">props</span>: [<span class="string">&quot;content&quot;</span>],</span></span><br><span class="line"><span class="javascript">        <span class="attr">template</span>: <span class="string">`&lt;div @click=&quot;outData&quot;&gt;&#123;&#123;content&#125;&#125;&lt;/div&gt;`</span>, <span class="comment">//绑定点击事件outData</span></span></span><br><span class="line"><span class="javascript">        <span class="function"><span class="title">data</span>(<span class="params"></span>)</span> &#123;</span></span><br><span class="line"><span class="javascript">          <span class="keyword">return</span> &#123;</span></span><br><span class="line"><span class="javascript">            <span class="attr">sonData</span>: <span class="string">&quot;I am from son&quot;</span></span></span><br><span class="line"><span class="javascript">          &#125;;</span></span><br><span class="line"><span class="javascript">        &#125;,</span></span><br><span class="line"><span class="javascript">        <span class="attr">methods</span>: &#123;</span></span><br><span class="line"><span class="javascript">          <span class="function"><span class="title">outData</span>(<span class="params"></span>)</span> &#123;</span></span><br><span class="line"><span class="javascript">            <span class="built_in">this</span>.$emit(<span class="string">&quot;transfer&quot;</span>, <span class="built_in">this</span>.sonData, <span class="string">&quot;my name is son&quot;</span>); <span class="comment">//将数据传递给父级</span></span></span><br><span class="line"><span class="javascript">          &#125;</span></span><br><span class="line"><span class="javascript">        &#125;</span></span><br><span class="line"><span class="javascript">      &#125;</span></span><br><span class="line"><span class="javascript">    &#125;,</span></span><br><span class="line"><span class="javascript">    <span class="attr">methods</span>: &#123;</span></span><br><span class="line"><span class="javascript">      <span class="function"><span class="title">getData</span>(<span class="params">sonData</span>)</span> &#123;</span></span><br><span class="line"><span class="javascript">        <span class="comment">//形参对应传递的数据</span></span></span><br><span class="line"><span class="javascript">        <span class="built_in">this</span>.val = sonData; <span class="comment">//&quot;I am from son&quot;</span></span></span><br><span class="line"><span class="javascript">      &#125;</span></span><br><span class="line"><span class="javascript">    &#125;</span></span><br><span class="line"><span class="javascript">  &#125;);</span></span><br><span class="line"><span class="javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>

<ul>
<li>在子组件中通过自定义事件进行传值，第一个参数为监听事件名，第二参数为传递的数据</li>
<li>在父组件上通过监听事件，通过对应的事件处理程序进行处理，事件处理程序的参数对应接收的数据</li>
</ul>
<h4 id="（3）单向数据流"><a href="#（3）单向数据流" class="headerlink" title="（3）单向数据流"></a>（3）单向数据流</h4><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;app&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">my-component</span> <span class="attr">:content</span>=<span class="string">&quot;val&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">my-component</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">my-component</span> <span class="attr">:content</span>=<span class="string">&quot;val&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">my-component</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="javascript"></span></span><br><span class="line"><span class="javascript">  <span class="keyword">let</span> vm = <span class="keyword">new</span> Vue(&#123;</span></span><br><span class="line"><span class="javascript">    <span class="attr">el</span>: <span class="string">&quot;#app&quot;</span>,</span></span><br><span class="line"><span class="javascript">    <span class="attr">data</span>: &#123;</span></span><br><span class="line"><span class="javascript">      <span class="attr">val</span>: [<span class="number">10</span>, <span class="number">20</span>, <span class="number">30</span>]</span></span><br><span class="line"><span class="javascript">    &#125;,</span></span><br><span class="line"><span class="javascript">    <span class="attr">components</span>: &#123;</span></span><br><span class="line"><span class="javascript">      <span class="attr">myComponent</span>: &#123;</span></span><br><span class="line"><span class="javascript">        <span class="attr">props</span>: [<span class="string">&quot;content&quot;</span>],</span></span><br><span class="line"><span class="javascript">        <span class="comment">//使用克隆后自身的值，组件之间不会相互影响</span></span></span><br><span class="line"><span class="javascript">        <span class="comment">//使用父级传入的引用值，组件之间可能会相互影响</span></span></span><br><span class="line"><span class="javascript">        <span class="attr">template</span>: <span class="string">`&lt;div&gt;&lt;div @click=&quot;changeData&quot;&gt;&#123;&#123;content&#125;&#125;&lt;/div&gt;&lt;h3 @click=&quot;changeSelfData&quot;&gt;&#123;&#123;newContent&#125;&#125;&lt;/h3&gt;&lt;/div&gt;`</span>,</span></span><br><span class="line"><span class="javascript">        <span class="function"><span class="title">data</span>(<span class="params"></span>)</span> &#123;</span></span><br><span class="line"><span class="javascript">          <span class="keyword">return</span> &#123;</span></span><br><span class="line"><span class="javascript">            <span class="attr">newContent</span>: <span class="built_in">this</span>.content.concat([]) <span class="comment">//深度克隆</span></span></span><br><span class="line"><span class="javascript">          &#125;;</span></span><br><span class="line"><span class="javascript">        &#125;,</span></span><br><span class="line"><span class="javascript">        <span class="attr">methods</span>: &#123;</span></span><br><span class="line"><span class="javascript">          <span class="function"><span class="title">changeData</span>(<span class="params"></span>)</span> &#123;</span></span><br><span class="line"><span class="javascript">            <span class="built_in">this</span>.content.push(<span class="string">&quot;受到影响&quot;</span>); <span class="comment">//改变父级传入的引用值可能对父级、其它组件造成影响</span></span></span><br><span class="line"><span class="javascript">          &#125;,</span></span><br><span class="line"><span class="javascript">          <span class="function"><span class="title">changeSelfData</span>(<span class="params"></span>)</span> &#123;</span></span><br><span class="line"><span class="javascript">            <span class="built_in">this</span>.newContent.push(<span class="string">&quot;互不影响&quot;</span>); <span class="comment">//改变自身的值，不会造成父级改变而影响到其它组件</span></span></span><br><span class="line"><span class="javascript">          &#125;</span></span><br><span class="line"><span class="javascript">        &#125;</span></span><br><span class="line"><span class="javascript">      &#125;</span></span><br><span class="line"><span class="javascript">    &#125;</span></span><br><span class="line"><span class="javascript">  &#125;);</span></span><br><span class="line"><span class="javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>

<ul>
<li>所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定：父级 prop 的更新会向下流动到子组件中，但是反过来则不行。这样会防止从子组件意外改变父级组件的状态，从而导致你的应用的数据流向难以理解。</li>
<li>额外的，每次父级组件发生更新时，子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。如果你这样做了，Vue 会在浏览器的控制台中发出警告。</li>
</ul>
<h4 id="（4）prop-验证"><a href="#（4）prop-验证" class="headerlink" title="（4）prop 验证"></a>（4）prop 验证</h4><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;app&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">my-component</span> <span class="attr">title</span>=<span class="string">&quot;hello&quot;</span> <span class="attr">:content</span>=<span class="string">&quot;val&quot;</span> <span class="attr">:str</span>=<span class="string">&quot;success&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">my-component</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="javascript"></span></span><br><span class="line"><span class="javascript">  <span class="keyword">let</span> vm = <span class="keyword">new</span> Vue(&#123;</span></span><br><span class="line"><span class="javascript">    <span class="attr">el</span>: <span class="string">&quot;#app&quot;</span>,</span></span><br><span class="line"><span class="javascript">    <span class="attr">data</span>: &#123;</span></span><br><span class="line"><span class="javascript">      <span class="attr">val</span>: [<span class="number">10</span>, <span class="number">20</span>, <span class="number">30</span>]</span></span><br><span class="line"><span class="javascript">    &#125;,</span></span><br><span class="line"><span class="javascript">    <span class="attr">components</span>: &#123;</span></span><br><span class="line"><span class="javascript">      <span class="attr">myComponent</span>: &#123;</span></span><br><span class="line"><span class="javascript">        <span class="attr">props</span>: &#123;</span></span><br><span class="line"><span class="javascript">          <span class="attr">title</span>: <span class="built_in">String</span>, <span class="comment">//Number/Boolean/Array/Object/Date/Function/Symbol</span></span></span><br><span class="line"><span class="javascript"></span></span><br><span class="line"><span class="javascript">          <span class="attr">content</span>: &#123;</span></span><br><span class="line"><span class="javascript">            <span class="attr">type</span>: [<span class="built_in">Array</span>, <span class="built_in">Object</span>], <span class="comment">//[String, Array] 期望类型,可以是多种类型（用数组列表）之一</span></span></span><br><span class="line"><span class="javascript">            <span class="attr">default</span>: <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">              <span class="keyword">return</span> [<span class="number">10</span>, <span class="number">20</span>]; <span class="comment">//数组或对象默认值必须用工厂函数获取</span></span></span><br><span class="line"><span class="javascript">            &#125;</span></span><br><span class="line"><span class="javascript">          &#125;,</span></span><br><span class="line"><span class="javascript"></span></span><br><span class="line"><span class="javascript">          <span class="attr">str</span>: &#123;</span></span><br><span class="line"><span class="javascript">            <span class="attr">type</span>: <span class="built_in">String</span>,</span></span><br><span class="line"><span class="javascript">            <span class="attr">required</span>: <span class="literal">true</span>, <span class="comment">//是否必须传入</span></span></span><br><span class="line"><span class="javascript">            <span class="attr">viewport</span>: <span class="function"><span class="keyword">function</span>(<span class="params">value</span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">              <span class="comment">//自定义验证，返回值true代表通过</span></span></span><br><span class="line"><span class="javascript">              <span class="keyword">return</span> [<span class="string">&quot;success&quot;</span>, <span class="string">&quot;warning&quot;</span>, <span class="string">&quot;danger&quot;</span>].indexOf(value) !== -<span class="number">1</span>;</span></span><br><span class="line"><span class="javascript">            &#125;</span></span><br><span class="line"><span class="javascript">          &#125;</span></span><br><span class="line"><span class="javascript">        &#125;</span></span><br><span class="line"><span class="javascript">      &#125;</span></span><br><span class="line"><span class="javascript">    &#125;</span></span><br><span class="line"><span class="javascript">  &#125;);</span></span><br><span class="line"><span class="javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>

<ul>
<li>为了定制 prop 的验证方式，你可以为 props 中的值提供一个带有验证需求的对象，而不是一个字符串数组。</li>
<li>数组或对象默认值必须用工厂函数获取</li>
<li>类型检测支持：String/Number/Boolean/Array/Object/Date/Function/Symbol</li>
</ul>
<hr>
<h3 id="3-动态组件"><a href="#3-动态组件" class="headerlink" title="3.动态组件"></a>3.动态组件</h3><h4 id="（1）component-is"><a href="#（1）component-is" class="headerlink" title="（1）component:is"></a>（1）component:is</h4><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;app&quot;</span>&gt;</span></span><br><span class="line">  <span class="comment">&lt;!-- &lt;com-one&gt;&lt;/com-one&gt; --&gt;</span></span><br><span class="line">  <span class="comment">&lt;!-- &lt;com-two&gt;&lt;/com-two&gt; --&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">component</span> <span class="attr">is</span>=<span class="string">&quot;comOne&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">component</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">component</span> <span class="attr">is</span>=<span class="string">&quot;comTwo&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">component</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">component</span> <span class="attr">:is</span>=<span class="string">&quot;type&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">component</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="javascript"></span></span><br><span class="line"><span class="javascript">  <span class="keyword">let</span> vm = <span class="keyword">new</span> Vue(&#123;</span></span><br><span class="line"><span class="javascript">    <span class="attr">el</span>: <span class="string">&quot;#app&quot;</span>,</span></span><br><span class="line"><span class="javascript">    <span class="attr">data</span>: &#123;</span></span><br><span class="line"><span class="javascript">      <span class="attr">type</span>: <span class="string">&quot;comThree&quot;</span></span></span><br><span class="line"><span class="javascript">    &#125;,</span></span><br><span class="line"><span class="javascript">    <span class="attr">components</span>: &#123;</span></span><br><span class="line"><span class="javascript">      <span class="attr">comOne</span>: &#123;</span></span><br><span class="line"><span class="javascript">        <span class="attr">template</span>: <span class="string">&quot;&lt;h1&gt;hello&lt;/h1&gt;&quot;</span></span></span><br><span class="line"><span class="javascript">      &#125;,</span></span><br><span class="line"><span class="javascript">      <span class="attr">comTwo</span>: &#123;</span></span><br><span class="line"><span class="javascript">        <span class="attr">template</span>: <span class="string">&quot;&lt;h2&gt;world&lt;/h2&gt;&quot;</span></span></span><br><span class="line"><span class="javascript">      &#125;,</span></span><br><span class="line"><span class="javascript">      <span class="attr">comTwo</span>: &#123;</span></span><br><span class="line"><span class="javascript">        <span class="attr">template</span>: <span class="string">&quot;&lt;h3&gt;!!!&lt;/h3&gt;&quot;</span></span></span><br><span class="line"><span class="javascript">      &#125;</span></span><br><span class="line"><span class="javascript">    &#125;</span></span><br><span class="line"><span class="javascript">  &#125;);</span></span><br><span class="line"><span class="javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>

<ul>
<li>出了组件名作为标签来使用组件外，我们还可以使用统一 component 标签，并用 is 属性来绑定使用哪一个组件</li>
<li>我们还可以使用动态绑定 v-bind:is 来动态的切换组件</li>
</ul>
<h4 id="（2）keep-alive"><a href="#（2）keep-alive" class="headerlink" title="（2）keep-alive"></a>（2）keep-alive</h4><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;app&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">button</span> @<span class="attr">click</span>=<span class="string">&quot;change&quot;</span>&gt;</span>切换<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">keep-alive</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">component</span> <span class="attr">:is</span>=<span class="string">&quot;type&quot;</span>&gt;</span><span class="tag">&lt;<span class="name">component</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">keep-alive</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="javascript"></span></span><br><span class="line"><span class="javascript">    <span class="keyword">let</span> vm = <span class="keyword">new</span> Vue(&#123;</span></span><br><span class="line"><span class="javascript">      <span class="attr">el</span>: <span class="string">&quot;#app&quot;</span>,</span></span><br><span class="line"><span class="javascript">      <span class="attr">data</span>: &#123;</span></span><br><span class="line"><span class="javascript">        <span class="attr">type</span>: <span class="string">&quot;comOne&quot;</span></span></span><br><span class="line"><span class="javascript">      &#125;,</span></span><br><span class="line"><span class="javascript">      <span class="attr">methods</span>: &#123;</span></span><br><span class="line"><span class="javascript">        <span class="function"><span class="title">change</span>(<span class="params"></span>)</span>&#123;</span></span><br><span class="line"><span class="javascript">          <span class="built_in">this</span>.type = <span class="built_in">this</span>.type === <span class="string">&quot;comOne&quot;</span> ? <span class="string">&quot;comTwo&quot;</span> : <span class="string">&quot;comOne&quot;</span>;</span></span><br><span class="line"><span class="javascript">        &#125;</span></span><br><span class="line"><span class="javascript">      &#125;,</span></span><br><span class="line"><span class="javascript">      <span class="attr">components</span>: &#123;</span></span><br><span class="line"><span class="javascript">        <span class="attr">comOne</span>: &#123;</span></span><br><span class="line"><span class="javascript">          <span class="attr">template</span>: <span class="string">&quot;&lt;div&gt;账号：&lt;input type=&#x27;text&#x27;&gt;&lt;/div&gt;&quot;</span>,</span></span><br><span class="line"><span class="javascript">        &#125;,</span></span><br><span class="line"><span class="javascript">        <span class="attr">comTwo</span>: &#123;</span></span><br><span class="line"><span class="javascript">          <span class="attr">template</span>: <span class="string">&quot;&lt;div&gt;密码：&lt;input type=&#x27;password&#x27;&gt;&lt;/div&gt;&quot;</span>,</span></span><br><span class="line"><span class="javascript">        &#125;</span></span><br><span class="line"><span class="javascript">      &#125;</span></span><br><span class="line"><span class="javascript">    &#125;);</span></span><br><span class="line"><span class="javascript">  </span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>

<ul>
<li>当在这些组件之间切换的时候，你有时会想保持这些组件的状态，以避免反复重渲染导致的性能问题。</li>
<li>你每次切换新标签的时候，Vue 都创建了一个新的 currentTabComponent 实例。</li>
<li>重新创建动态组件的行为通常是非常有用的，但有时候，我们更希望那些标签的组件实例能够被在它们第一次被创建的时候缓存下来。</li>
<li>我们可以用一个 &lt;keep-alive&gt; 元素将其动态组件包裹起来。要求被切换到的组件都有自己的名字，不论是通过组件的 name 选项还是局部/全局注册。</li>
</ul>
<hr>
<h3 id="4-插槽"><a href="#4-插槽" class="headerlink" title="4.插槽"></a>4.插槽</h3><h4 id="（1）匿名、具名插槽"><a href="#（1）匿名、具名插槽" class="headerlink" title="（1）匿名、具名插槽"></a>（1）匿名、具名插槽</h4><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;app&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">component</span> <span class="attr">is</span>=<span class="string">&quot;com-one&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">span</span>&gt;</span>2月2日<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">component</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">component</span> <span class="attr">is</span>=<span class="string">&quot;com-two&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">span</span> <span class="attr">slot</span>=<span class="string">&quot;header&quot;</span>&gt;</span>太阳<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">span</span>&gt;</span>月亮<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">span</span> <span class="attr">slot</span>=<span class="string">&quot;footer&quot;</span>&gt;</span>星星<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">component</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="handlebars"><span class="xml"></span></span></span><br><span class="line"><span class="xml"><span class="handlebars">  let vm = new Vue(&#123;</span></span></span><br><span class="line"><span class="xml"><span class="handlebars">    el: &quot;#app&quot;,</span></span></span><br><span class="line"><span class="xml"><span class="handlebars">    components: &#123;</span></span></span><br><span class="line"><span class="xml"><span class="handlebars">      comOne: &#123;//匿名插槽</span></span></span><br><span class="line"><span class="xml"><span class="handlebars">        template: `<span class="tag">&lt;<span class="name">div</span>&gt;</span></span></span></span><br><span class="line"><span class="xml"><span class="handlebars">                    <span class="tag">&lt;<span class="name">span</span>&gt;</span>2020年<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span></span></span><br><span class="line"><span class="xml"><span class="handlebars">                    <span class="tag">&lt;<span class="name">slot</span>&gt;</span><span class="tag">&lt;/<span class="name">slot</span>&gt;</span></span></span></span><br><span class="line"><span class="xml"><span class="handlebars">                  <span class="tag">&lt;/<span class="name">div</span>&gt;</span>`,</span></span></span><br><span class="line"><span class="xml"><span class="handlebars">      &#125;,</span></span></span><br><span class="line"><span class="xml"><span class="handlebars">      comTwo: &#123;//具名插槽（匿名默认是default）</span></span></span><br><span class="line"><span class="xml"><span class="handlebars">        template: `<span class="tag">&lt;<span class="name">div</span>&gt;</span></span></span></span><br><span class="line"><span class="xml"><span class="handlebars">                    <span class="tag">&lt;<span class="name">h1</span>&gt;</span></span></span></span><br><span class="line"><span class="xml"><span class="handlebars">                      <span class="tag">&lt;<span class="name">slot</span> <span class="attr">name</span>=<span class="string">&#x27;header&#x27;</span>&gt;</span><span class="tag">&lt;/<span class="name">slot</span>&gt;</span></span></span></span><br><span class="line"><span class="xml"><span class="handlebars">                    <span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span></span></span><br><span class="line"><span class="xml"><span class="handlebars">                    <span class="tag">&lt;<span class="name">h2</span>&gt;</span></span></span></span><br><span class="line"><span class="xml"><span class="handlebars">                      <span class="tag">&lt;<span class="name">slot</span> <span class="attr">name</span>=<span class="string">&quot;default&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">slot</span>&gt;</span></span></span></span><br><span class="line"><span class="xml"><span class="handlebars">                    <span class="tag">&lt;/<span class="name">h2</span>&gt;</span></span></span></span><br><span class="line"><span class="xml"><span class="handlebars">                    <span class="tag">&lt;<span class="name">h3</span>&gt;</span></span></span></span><br><span class="line"><span class="xml"><span class="handlebars">                      <span class="tag">&lt;<span class="name">slot</span> <span class="attr">name</span>=<span class="string">&quot;footer&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">slot</span>&gt;</span></span></span></span><br><span class="line"><span class="xml"><span class="handlebars">                    <span class="tag">&lt;/<span class="name">h3</span>&gt;</span></span></span></span><br><span class="line"><span class="xml"><span class="handlebars">                  <span class="tag">&lt;/<span class="name">div</span>&gt;</span>`,</span></span></span><br><span class="line"><span class="xml"><span class="handlebars">      &#125;</span></span></span><br><span class="line"><span class="xml"><span class="handlebars">    &#125;</span></span></span><br><span class="line"><span class="xml"><span class="handlebars">  &#125;);</span></span></span><br><span class="line"><span class="xml"><span class="handlebars"></span></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h4 id="（2）作用域插槽"><a href="#（2）作用域插槽" class="headerlink" title="（2）作用域插槽"></a>（2）作用域插槽</h4><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;app&quot;</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- 父级将数据传递给子级 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">com-one</span> <span class="attr">:list</span>=<span class="string">&quot;list&quot;</span>&gt;</span></span><br><span class="line">      <span class="comment">&lt;!-- 父级声明一个作用域slot-scope, 对应子级作用域 --&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">template</span> <span class="attr">slot-scope</span>=<span class="string">&quot;scope&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">li</span>&gt;</span></span><br><span class="line">          <span class="comment">&lt;!-- 在这个作用域内可以使用子级绑定的数据 --&gt;</span></span><br><span class="line">          &#123;&#123;scope.item&#125;&#125; - &#123;&#123;scope.index&#125;&#125;</span><br><span class="line">        <span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">template</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">com-one</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">com-one</span> <span class="attr">:list</span>=<span class="string">&quot;list&quot;</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">template</span> <span class="attr">slot-scope</span>=<span class="string">&quot;scope&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">li</span>&gt;</span></span><br><span class="line">          &#123;&#123;scope.index&#125;&#125; - &#123;&#123;scope.item&#125;&#125;</span><br><span class="line">        <span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">template</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">com-one</span>&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="javascript"></span></span><br><span class="line"><span class="javascript">    <span class="keyword">let</span> vm = <span class="keyword">new</span> Vue(&#123;</span></span><br><span class="line"><span class="javascript">      <span class="attr">el</span>: <span class="string">&quot;#app&quot;</span>,</span></span><br><span class="line"><span class="javascript">      <span class="attr">data</span>: &#123;</span></span><br><span class="line"><span class="javascript">        <span class="attr">list</span>: [<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>]</span></span><br><span class="line"><span class="javascript">      &#125;,</span></span><br><span class="line"><span class="javascript">      <span class="attr">components</span>: &#123;</span></span><br><span class="line"><span class="javascript">        <span class="attr">comOne</span>: &#123;</span></span><br><span class="line"><span class="javascript">          <span class="attr">props</span>: [<span class="string">&quot;list&quot;</span>],<span class="comment">//子级接受数据</span></span></span><br><span class="line"><span class="javascript">          <span class="function"><span class="title">data</span>(<span class="params"></span>)</span>&#123;</span></span><br><span class="line"><span class="javascript">            <span class="keyword">return</span> &#123;</span></span><br><span class="line"><span class="javascript">              <span class="attr">newList</span>: <span class="built_in">this</span>.list.concat([])<span class="comment">//子级深度克隆数据，并使用克隆后的数据</span></span></span><br><span class="line"><span class="javascript">            &#125;</span></span><br><span class="line"><span class="javascript">          &#125;,</span></span><br><span class="line"><span class="javascript">          <span class="comment">//插槽列表渲染</span></span></span><br><span class="line"><span class="javascript">          <span class="comment">//绑定需要的数据（在slot-scope内）</span></span></span><br><span class="line"><span class="javascript">          <span class="attr">template</span>: <span class="string">`&lt;ul&gt;</span></span></span><br><span class="line"><span class="string"><span class="javascript">                        &lt;slot </span></span></span><br><span class="line"><span class="string"><span class="javascript">                          v-for=&#x27;(item, index) in newList&#x27; </span></span></span><br><span class="line"><span class="string"><span class="javascript">                          :key=&quot;index&quot;</span></span></span><br><span class="line"><span class="string"><span class="javascript">                          :item=&quot;item&quot;</span></span></span><br><span class="line"><span class="string"><span class="javascript">                          :index=&quot;index&quot;&gt;</span></span></span><br><span class="line"><span class="string"><span class="javascript">                        &lt;/slot&gt;</span></span></span><br><span class="line"><span class="string"><span class="javascript">                    &lt;/ul&gt;`</span>,</span></span><br><span class="line"><span class="javascript">        &#125;</span></span><br><span class="line"><span class="javascript">      &#125;</span></span><br><span class="line"><span class="javascript">    &#125;);</span></span><br><span class="line"><span class="javascript">  </span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>
<hr>
<h2 id="（三）实例"><a href="#（三）实例" class="headerlink" title="（三）实例"></a>（三）实例</h2><h3 id="1-new-Vue"><a href="#1-new-Vue" class="headerlink" title="1.new Vue()"></a>1.new Vue()</h3><h4 id="（1）vm"><a href="#（1）vm" class="headerlink" title="（1）vm"></a>（1）vm</h4><ul>
<li>虽然没有完全遵循 MVVM 模型，但是 Vue 的设计也受到了它的启发。因此在文档中经常会使用 vm (ViewModel 的缩写) 这个变量名表示 Vue 实例。</li>
</ul>
<h4 id="（2）data"><a href="#（2）data" class="headerlink" title="（2）data"></a>（2）data</h4><ul>
<li>当一个 Vue 实例被创建时，它将 data 对象中的所有的属性加入到 Vue 的响应式系统中。当这些属性的值发生改变时，视图将会产生“响应”，即匹配更新为新的值。</li>
<li>当这些数据改变时，视图会进行重渲染。值得注意的是只有当实例被创建时就已经存在于 data 中的属性才是响应式的。</li>
</ul>
<h4 id="（3）el、-mount-、template、render"><a href="#（3）el、-mount-、template、render" class="headerlink" title="（3）el、$mount()、template、render()"></a>（3）el、$mount()、template、render()</h4><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;app1&quot;</span>&gt;</span>&#123;&#123;val&#125;&#125;<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;app2&quot;</span>&gt;</span>&#123;&#123;val&#125;&#125;<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;app3&quot;</span>&gt;</span>&#123;&#123;val&#125;&#125;<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;app4&quot;</span>&gt;</span>&#123;&#123;val&#125;&#125;<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="javascript"></span></span><br><span class="line"><span class="javascript">  <span class="comment">//通过el属性挂载实例</span></span></span><br><span class="line"><span class="javascript">  <span class="keyword">let</span> vm1 = <span class="keyword">new</span> Vue(&#123;</span></span><br><span class="line"><span class="javascript">    <span class="attr">el</span>: <span class="string">&#x27;#app1&#x27;</span>,</span></span><br><span class="line"><span class="javascript">    <span class="attr">data</span>: &#123;</span></span><br><span class="line"><span class="javascript">      <span class="attr">val</span>: <span class="string">&quot;app1&quot;</span></span></span><br><span class="line"><span class="javascript">    &#125;</span></span><br><span class="line"><span class="javascript">  &#125;);</span></span><br><span class="line"><span class="javascript"></span></span><br><span class="line"><span class="javascript">  <span class="comment">//通过实例方法$Mount()挂载实例</span></span></span><br><span class="line"><span class="javascript">  <span class="keyword">let</span> vm2 = <span class="keyword">new</span> Vue(&#123;</span></span><br><span class="line"><span class="javascript">    <span class="attr">data</span>: &#123;</span></span><br><span class="line"><span class="javascript">      <span class="attr">val</span>: <span class="string">&quot;app2&quot;</span></span></span><br><span class="line"><span class="javascript">    &#125;</span></span><br><span class="line"><span class="javascript">  &#125;)</span></span><br><span class="line"><span class="javascript">  vm2.$mount(<span class="string">&quot;#app2&quot;</span>)</span></span><br><span class="line"><span class="javascript"></span></span><br><span class="line"><span class="javascript">  <span class="comment">//template会替换掉div#app3</span></span></span><br><span class="line"><span class="javascript">  <span class="comment">//template优于el和$mount()的outHtml()</span></span></span><br><span class="line"><span class="javascript">  <span class="keyword">let</span> vm3 = <span class="keyword">new</span> Vue(&#123;</span></span><br><span class="line"><span class="javascript">    <span class="attr">el</span>: <span class="string">&#x27;#app3&#x27;</span>,</span></span><br><span class="line"><span class="javascript">    <span class="attr">data</span>: &#123;</span></span><br><span class="line"><span class="javascript">      <span class="attr">val</span>: <span class="string">&quot;app3&quot;</span></span></span><br><span class="line"><span class="javascript">    &#125;,</span></span><br><span class="line"><span class="javascript">    <span class="attr">template</span>: <span class="string">&quot;&lt;h1&gt;&#123;&#123;val&#125;&#125;&lt;/h1&gt;&quot;</span></span></span><br><span class="line"><span class="javascript">  &#125;)</span></span><br><span class="line"><span class="javascript"></span></span><br><span class="line"><span class="javascript">  <span class="comment">//render优于template</span></span></span><br><span class="line"><span class="javascript">  <span class="keyword">let</span> vm4 = <span class="keyword">new</span> Vue(&#123;</span></span><br><span class="line"><span class="javascript">    <span class="attr">el</span>: <span class="string">&#x27;#app4&#x27;</span>,</span></span><br><span class="line"><span class="javascript">    <span class="attr">data</span>: &#123;</span></span><br><span class="line"><span class="javascript">      <span class="attr">val</span>: <span class="string">&quot;app4&quot;</span></span></span><br><span class="line"><span class="javascript">    &#125;,</span></span><br><span class="line"><span class="javascript">    <span class="attr">template</span>: <span class="string">&quot;&lt;h1&gt;&#123;&#123;val&#125;&#125;&lt;/h1&gt;&quot;</span>,</span></span><br><span class="line"><span class="javascript">    <span class="function"><span class="title">render</span>(<span class="params">h</span>)</span>&#123;<span class="comment">// h函数用于创建VNode</span></span></span><br><span class="line"><span class="javascript">      <span class="keyword">return</span> h(<span class="string">&quot;p&quot;</span>,&#123;</span></span><br><span class="line"><span class="javascript">        <span class="comment">//行间样式</span></span></span><br><span class="line"><span class="javascript">        <span class="attr">style</span>: &#123;</span></span><br><span class="line"><span class="javascript">          <span class="attr">color</span>: <span class="string">&quot;red&quot;</span></span></span><br><span class="line"><span class="javascript">        &#125;,</span></span><br><span class="line"><span class="javascript">        <span class="comment">//类名</span></span></span><br><span class="line"><span class="javascript">        <span class="attr">class</span>: [<span class="string">&#x27;bg&#x27;</span>],</span></span><br><span class="line"><span class="javascript">        <span class="comment">//Dom属性</span></span></span><br><span class="line"><span class="javascript">        <span class="attr">domProps</span>: &#123;</span></span><br><span class="line"><span class="javascript">          <span class="comment">// innerHTML: &quot;app&quot;//优于第三个参数</span></span></span><br><span class="line"><span class="javascript">        &#125;</span></span><br><span class="line"><span class="javascript">      &#125;,[h(<span class="string">&quot;h3&quot;</span>),h(<span class="string">&quot;h4&quot;</span>)]);</span></span><br><span class="line"><span class="javascript">    &#125;</span></span><br><span class="line"><span class="javascript">  &#125;)</span></span><br><span class="line"><span class="javascript"></span></span><br><span class="line"><span class="javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>
<ul>
<li>el、$mount()都是挂载实例</li>
<li>template时一个html字符串，会替换掉挂载的Dom,如果没有则使用挂载Dom的outHtml()</li>
<li>render()是产生虚拟Dom的函数，所返回的虚拟Dom会决定视图的内容</li>
</ul>
<h3 id="2-生命周期"><a href="#2-生命周期" class="headerlink" title="2.生命周期"></a>2.生命周期</h3><ul>
<li>生命周期钩子<img src="./lifecycle.png"></li>
</ul>
<hr>
<h2 id="（四）Vue-Cli"><a href="#（四）Vue-Cli" class="headerlink" title="（四）Vue-Cli"></a>（四）Vue-Cli</h2><h3 id="1-安装"><a href="#1-安装" class="headerlink" title="1.安装"></a>1.安装</h3><h4 id="（1）npm安装"><a href="#（1）npm安装" class="headerlink" title="（1）npm安装"></a>（1）npm安装</h4><blockquote>
<p>npm install -g @vue/cli<br>vue –version </p>
</blockquote>
<h4 id="（2）创建项目-cmd指令"><a href="#（2）创建项目-cmd指令" class="headerlink" title="（2）创建项目-cmd指令"></a>（2）创建项目-cmd指令</h4><blockquote>
<p>vue create vue-app</p>
</blockquote>
<ul>
<li><p><font color=red>解决git中上下按键选择无效问题？</font></p>
<ul>
<li>选择git bash 的安装目录，找到etc/bash.bashrc文件</li>
<li>文件末未添加 ：alias vue=’winpty vue.cmd’</li>
<li>重启git bash 即可</li>
</ul>
</li>
<li><p>清除预设</p>
<blockquote>
<p>C:/user/lhf/.vuerc</p>
</blockquote>
</li>
</ul>
<h4 id="（3）创建项目-UI"><a href="#（3）创建项目-UI" class="headerlink" title="（3）创建项目-UI"></a>（3）创建项目-UI</h4><blockquote>
<p>vue ui</p>
</blockquote>
<ul>
<li>回到创建页<blockquote>
<p>C:/user/lhf/vue-cli-ui/db.json</p>
</blockquote>
</li>
</ul>
<h4 id="（3）运行项目"><a href="#（3）运行项目" class="headerlink" title="（3）运行项目"></a>（3）运行项目</h4><ul>
<li><p>运行index.html</p>
<blockquote>
<p>npm run serve</p>
</blockquote>
</li>
<li><p>运行指定vue文件</p>
<blockquote>
<p>npm install -g @vue/cli-service-global<br>vue run serve helloworld</p>
</blockquote>
</li>
</ul>
<hr>
<h3 id="2-路由router"><a href="#2-路由router" class="headerlink" title="2.路由router"></a>2.路由router</h3><h4 id="（1）安装"><a href="#（1）安装" class="headerlink" title="（1）安装"></a>（1）安装</h4><blockquote>
<p>npm install vue-router –save<br>vue add router –save</p>
</blockquote>
<h4 id="（2）使用"><a href="#（2）使用" class="headerlink" title="（2）使用"></a>（2）使用</h4><ul>
<li>router.js<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> Vue <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span></span><br><span class="line"><span class="keyword">import</span> VueRouter <span class="keyword">from</span> <span class="string">&#x27;vue-router&#x27;</span></span><br><span class="line"><span class="keyword">import</span> Home <span class="keyword">from</span> <span class="string">&#x27;../views/Home.vue&#x27;</span></span><br><span class="line"><span class="keyword">import</span> About <span class="keyword">from</span> <span class="string">&#x27;../views/About.vue&#x27;</span></span><br><span class="line"><span class="keyword">import</span> Learn <span class="keyword">from</span> <span class="string">&#x27;../views/Learn.vue&#x27;</span></span><br><span class="line"><span class="keyword">import</span> Student <span class="keyword">from</span> <span class="string">&#x27;../views/Student.vue&#x27;</span></span><br><span class="line"><span class="keyword">import</span> Community <span class="keyword">from</span> <span class="string">&#x27;../views/Community.vue&#x27;</span></span><br><span class="line"><span class="keyword">import</span> Question <span class="keyword">from</span> <span class="string">&#x27;../components/community/question&#x27;</span></span><br><span class="line"><span class="keyword">import</span> Forum <span class="keyword">from</span> <span class="string">&#x27;../components/community/forum&#x27;</span></span><br><span class="line"><span class="keyword">import</span> Help <span class="keyword">from</span> <span class="string">&#x27;../components/community/help&#x27;</span></span><br><span class="line"><span class="keyword">import</span> Answer <span class="keyword">from</span> <span class="string">&#x27;../components/Answer&#x27;</span></span><br><span class="line"><span class="keyword">import</span> Error404 <span class="keyword">from</span> <span class="string">&#x27;../components/Error&#x27;</span></span><br><span class="line"></span><br><span class="line">Vue.use(VueRouter)</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> routes = [</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="attr">path</span>: <span class="string">&#x27;/home&#x27;</span>,</span><br><span class="line">    <span class="attr">name</span>: <span class="string">&#x27;home&#x27;</span>,</span><br><span class="line">    <span class="attr">alias</span>: <span class="string">&quot;/&quot;</span>, <span class="comment">//别名, 影响active</span></span><br><span class="line">    <span class="attr">components</span>: &#123;<span class="comment">//router-view复用</span></span><br><span class="line">      <span class="attr">default</span>: Home,</span><br><span class="line">      <span class="string">&quot;list&quot;</span>: Question</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="attr">path</span>: <span class="string">&#x27;/about&#x27;</span>,<span class="comment">//对用router-link to=path</span></span><br><span class="line">    <span class="attr">name</span>: <span class="string">&#x27;about&#x27;</span>,<span class="comment">//对用router-link :to=&#123;name: name&#125;</span></span><br><span class="line">    <span class="attr">component</span>: About</span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="attr">path</span>: <span class="string">&#x27;/community&#x27;</span>,</span><br><span class="line">    <span class="attr">name</span>: <span class="string">&#x27;community&#x27;</span>,</span><br><span class="line">    <span class="attr">component</span>: Community,</span><br><span class="line">    <span class="attr">redirect</span>: <span class="string">&quot;/community/question&quot;</span>,<span class="comment">//路由重定向</span></span><br><span class="line">    <span class="attr">meta</span>: &#123;<span class="comment">//原信息，子组件实例的$route.matched[0].meta可以访问到，在访问不到实例之前，to上面也可以访问</span></span><br><span class="line">      <span class="attr">login</span>: <span class="literal">false</span></span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="attr">children</span>: [<span class="comment">//嵌套路由</span></span><br><span class="line">      &#123;</span><br><span class="line">        <span class="comment">// path: &#x27;/community/question&#x27;,//绝对路径</span></span><br><span class="line">        <span class="attr">path</span>: <span class="string">&#x27;question&#x27;</span>,<span class="comment">//相对路径简写形式，不能出现/</span></span><br><span class="line">        <span class="attr">name</span>: <span class="string">&quot;question&quot;</span>,</span><br><span class="line">        <span class="attr">component</span>: Question</span><br><span class="line">      &#125;,</span><br><span class="line">      &#123;</span><br><span class="line">        <span class="attr">path</span>: <span class="string">&#x27;forum&#x27;</span>,</span><br><span class="line">        <span class="attr">name</span>: <span class="string">&quot;forum&quot;</span>,</span><br><span class="line">        <span class="attr">component</span>: Forum</span><br><span class="line">      &#125;,</span><br><span class="line">      &#123;</span><br><span class="line">        <span class="attr">path</span>: <span class="string">&#x27;help&#x27;</span>,</span><br><span class="line">        <span class="attr">name</span>: <span class="string">&quot;help&quot;</span>,</span><br><span class="line">        <span class="attr">component</span>: Help</span><br><span class="line">      &#125;,</span><br><span class="line">    ]</span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="attr">path</span>: <span class="string">&quot;/answer/:id&quot;</span>,<span class="comment">//动态路由</span></span><br><span class="line">    <span class="attr">name</span>: <span class="string">&quot;answer&quot;</span>,</span><br><span class="line">    <span class="attr">component</span>: Answer</span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="attr">path</span>: <span class="string">&quot;/404&quot;</span>,<span class="comment">//404</span></span><br><span class="line">    <span class="attr">name</span>: <span class="string">&quot;error&quot;</span>,</span><br><span class="line">    <span class="attr">component</span>: Error404</span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="attr">path</span>: <span class="string">&#x27;*&#x27;</span>,<span class="comment">//未匹配重定向</span></span><br><span class="line">    <span class="function"><span class="title">redirect</span>(<span class="params">to</span>)</span>&#123;</span><br><span class="line">      <span class="keyword">if</span>(to.path === <span class="string">&quot;/&quot;</span>)&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&#x27;/home&#x27;</span></span><br><span class="line">      &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> &#123;</span><br><span class="line">          <span class="attr">name</span>: <span class="string">&quot;error&quot;</span></span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">]</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> router = <span class="keyword">new</span> VueRouter(&#123;</span><br><span class="line">  <span class="attr">linkActiveClass</span>: <span class="string">&quot;active&quot;</span>,<span class="comment">//重命名</span></span><br><span class="line">  <span class="attr">mode</span>: <span class="string">&#x27;history&#x27;</span>,</span><br><span class="line">  <span class="attr">base</span>: process.env.BASE_URL,</span><br><span class="line">  routes</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> router</span><br><span class="line"></span><br></pre></td></tr></table></figure></li>
<li>component.vue</li>
</ul>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">template</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;app&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">ul</span> <span class="attr">id</span>=<span class="string">&quot;nav&quot;</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">router-link</span> <span class="attr">tag</span>=<span class="string">&quot;li&quot;</span> <span class="attr">to</span>=<span class="string">&quot;/&quot;</span>&gt;</span>Home<span class="tag">&lt;/<span class="name">router-link</span>&gt;</span> |</span><br><span class="line">      <span class="tag">&lt;<span class="name">router-link</span> <span class="attr">tag</span>=<span class="string">&quot;li&quot;</span> <span class="attr">to</span>=<span class="string">&quot;/about&quot;</span>&gt;</span>About<span class="tag">&lt;/<span class="name">router-link</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">ul</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">router-view</span>/&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- 动态绑定 --&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- 动态路由 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">router-link</span> <span class="attr">:to</span>=<span class="string">&quot;&#123;name: &#x27;myHome&#x27;, params: &#123;id: item.id&#125;&#125;&quot;</span>&gt;</span>myHome<span class="tag">&lt;/<span class="name">router-link</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">router-link</span> <span class="attr">:to</span>=<span class="string">&quot;&#123;name: about&#125;&quot;</span>&gt;</span>myAbout<span class="tag">&lt;/<span class="name">router-link</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">router-view</span>/&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">template</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="javascript"></span></span><br><span class="line"><span class="javascript">  <span class="keyword">export</span> <span class="keyword">default</span> &#123;</span></span><br><span class="line"><span class="javascript">    <span class="function"><span class="title">create</span>(<span class="params"></span>)</span>&#123;</span></span><br><span class="line"><span class="javascript">      <span class="built_in">this</span>.$route.params.id<span class="comment">//动态路由传值接收</span></span></span><br><span class="line"><span class="javascript">    &#125;</span></span><br><span class="line"><span class="javascript">  &#125;</span></span><br><span class="line"><span class="javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>
<ul>
<li>路由: vue-router</li>
<li>路由嵌套: children[]</li>
<li>动态路由: ‘/path/:id’ :to=”{name: path, params:{id: item.id}}” create(){this.$route.params.id}</li>
<li>路由重定向: redirect: ‘/newPath’</li>
<li>路由别名：alias</li>
<li>路由Class: LinkActiveClass</li>
<li>router-link应用: tag=”li”</li>
<li>router-view复用: components[]</li>
<li>原信息：meta</li>
</ul>
<hr>
<h4 id="（3）导航守卫"><a href="#（3）导航守卫" class="headerlink" title="（3）导航守卫"></a>（3）导航守卫</h4><ul>
<li>全局守卫</li>
<li>Router实例方法：beforeEach(function(to, from, next){})<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> router = <span class="keyword">new</span> VueRouter(&#123;</span><br><span class="line">  <span class="attr">linkActiveClass</span>: <span class="string">&quot;active&quot;</span>,<span class="comment">//重命名</span></span><br><span class="line">  <span class="attr">mode</span>: <span class="string">&#x27;history&#x27;</span>,</span><br><span class="line">  <span class="attr">base</span>: process.env.BASE_URL,</span><br><span class="line">  routes</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">//导航守卫 全局守卫</span></span><br><span class="line"><span class="comment">// to: 去哪里</span></span><br><span class="line"><span class="comment">// from: 从哪来</span></span><br><span class="line"><span class="comment">// next(param)</span></span><br><span class="line"><span class="comment">//             param === false 不许进，从哪来回哪去</span></span><br><span class="line"><span class="comment">//             param === path 去指定地方</span></span><br><span class="line"><span class="comment">//             空 允许进</span></span><br><span class="line">router.beforeEach(<span class="function"><span class="keyword">function</span>(<span class="params">to, <span class="keyword">from</span>, next</span>)</span>&#123;</span><br><span class="line">  <span class="keyword">if</span>(to.path === <span class="string">&quot;/community/question&quot;</span>)&#123;</span><br><span class="line">    <span class="keyword">let</span> result = confirm(<span class="string">&quot;你还没有登录，要前往登录吗？&quot;</span>);</span><br><span class="line">    <span class="keyword">if</span>(result)&#123;</span><br><span class="line">      next(&#123;<span class="attr">name</span>: <span class="string">&#x27;user&#x27;</span>&#125;);</span><br><span class="line">    &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">      next(<span class="literal">false</span>)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">    next()</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure></li>
<li>路由独享守卫-路由（仅仅可以守卫该路径下的组件）</li>
<li>routes内属性方法：beforeEnter(to, from, next){}<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">    <span class="attr">path</span>: <span class="string">&#x27;/community&#x27;</span>,</span><br><span class="line">    <span class="attr">name</span>: <span class="string">&#x27;community&#x27;</span>,</span><br><span class="line">    <span class="attr">component</span>: Community,</span><br><span class="line">    <span class="attr">redirect</span>: <span class="string">&quot;/community/question&quot;</span>,<span class="comment">//重定向</span></span><br><span class="line">    <span class="attr">children</span>: [</span><br><span class="line">      &#123;</span><br><span class="line">        <span class="comment">// path: &#x27;/community/question&#x27;,</span></span><br><span class="line">        <span class="attr">path</span>: <span class="string">&#x27;question&#x27;</span>,</span><br><span class="line">        <span class="attr">name</span>: <span class="string">&quot;question&quot;</span>,</span><br><span class="line">        <span class="attr">component</span>: Question,</span><br><span class="line">        <span class="function"><span class="title">beforeEnter</span>(<span class="params">to, <span class="keyword">from</span>, next</span>)</span>&#123;</span><br><span class="line">          <span class="keyword">let</span> result = confirm(<span class="string">&quot;你还没有登录，要前往登录吗？&quot;</span>);</span><br><span class="line">          <span class="keyword">if</span>(result)&#123;</span><br><span class="line">            next(&#123;<span class="attr">name</span>: <span class="string">&#x27;user&#x27;</span>&#125;);</span><br><span class="line">          &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">            next(<span class="literal">false</span>)</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;,</span><br><span class="line">      &#123;</span><br><span class="line">        <span class="attr">path</span>: <span class="string">&#x27;forum&#x27;</span>,</span><br><span class="line">        <span class="attr">name</span>: <span class="string">&quot;forum&quot;</span>,</span><br><span class="line">        <span class="attr">component</span>: Forum</span><br><span class="line">      &#125;,</span><br><span class="line">      &#123;</span><br><span class="line">        <span class="attr">path</span>: <span class="string">&#x27;help&#x27;</span>,</span><br><span class="line">        <span class="attr">name</span>: <span class="string">&quot;help&quot;</span>,</span><br><span class="line">        <span class="attr">component</span>: Help</span><br><span class="line">      &#125;,</span><br><span class="line">      &#123;</span><br><span class="line">        <span class="attr">path</span>: <span class="string">&#x27;user&#x27;</span>,</span><br><span class="line">        <span class="attr">name</span>: <span class="string">&quot;user&quot;</span>,</span><br><span class="line">        <span class="attr">component</span>: User</span><br><span class="line">      &#125;,</span><br><span class="line">    ]</span><br><span class="line">  &#125;,</span><br></pre></td></tr></table></figure></li>
<li>组件内守卫-组件（可守卫所有该组件出现的地方）</li>
<li>组件属性方法：beforeRouteEnter(to, from, next)<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="javascript"></span></span><br><span class="line"><span class="javascript">  <span class="keyword">export</span> <span class="keyword">default</span> &#123;</span></span><br><span class="line"><span class="javascript">    <span class="function"><span class="title">beforeRouteEnter</span>(<span class="params">to, <span class="keyword">from</span>, next</span>)</span> &#123;</span></span><br><span class="line"><span class="javascript">      <span class="keyword">if</span>(to.matched[<span class="number">0</span>].meta.login)&#123;</span></span><br><span class="line"><span class="javascript">        next();</span></span><br><span class="line"><span class="javascript">        <span class="keyword">return</span>;</span></span><br><span class="line"><span class="javascript">      &#125;</span></span><br><span class="line"><span class="javascript">      <span class="keyword">let</span> result = confirm(<span class="string">&quot;你还没有登录，要前往登录吗？&quot;</span>);</span></span><br><span class="line"><span class="javascript">      <span class="keyword">if</span> (result) &#123;</span></span><br><span class="line"><span class="javascript">        next(&#123;</span></span><br><span class="line"><span class="javascript">          <span class="attr">name</span>: <span class="string">&#x27;user&#x27;</span></span></span><br><span class="line"><span class="javascript">        &#125;);</span></span><br><span class="line"><span class="javascript">      &#125; <span class="keyword">else</span> &#123;</span></span><br><span class="line"><span class="javascript">        next(<span class="literal">false</span>)</span></span><br><span class="line"><span class="javascript">      &#125;</span></span><br><span class="line"><span class="javascript">    &#125;,</span></span><br><span class="line"><span class="javascript">    <span class="function"><span class="title">beforeRouteLeave</span>(<span class="params">to, <span class="keyword">from</span>, next</span>)</span>&#123;</span></span><br><span class="line"><span class="javascript">      <span class="keyword">let</span> result = confirm(<span class="string">&quot;确定要离开吗？&quot;</span>);</span></span><br><span class="line"><span class="javascript">      <span class="keyword">if</span>(result)&#123;</span></span><br><span class="line"><span class="javascript">        next()</span></span><br><span class="line"><span class="javascript">      &#125;<span class="keyword">else</span>&#123;</span></span><br><span class="line"><span class="javascript">        next(<span class="literal">false</span>)</span></span><br><span class="line"><span class="javascript">      &#125;</span></span><br><span class="line"><span class="javascript">    &#125;,</span></span><br><span class="line"><span class="javascript">    <span class="function"><span class="title">data</span>(<span class="params"></span>)</span> &#123;</span></span><br><span class="line"><span class="javascript">      <span class="keyword">return</span> &#123;</span></span><br><span class="line"><span class="javascript">        <span class="attr">questions</span>: [&#123;</span></span><br><span class="line"><span class="javascript">            <span class="attr">id</span>: <span class="number">202001</span>,</span></span><br><span class="line"><span class="javascript">            <span class="attr">question</span>: <span class="string">&quot;月亮太阳看起来为什么一样大?&quot;</span>,</span></span><br><span class="line"><span class="javascript">            <span class="attr">answer</span>: <span class="string">&quot;从地球上望月球，它看上去与太阳的大小差不多，造成这种错觉是距离奇怪的安排.&quot;</span></span></span><br><span class="line"><span class="javascript">          &#125;,</span></span><br><span class="line"><span class="javascript">          &#123;</span></span><br><span class="line"><span class="javascript">            <span class="attr">id</span>: <span class="number">202002</span>,</span></span><br><span class="line"><span class="javascript">            <span class="attr">question</span>: <span class="string">&quot;墨为什么不褪色?&quot;</span>,</span></span><br><span class="line"><span class="javascript">            <span class="attr">answer</span>: <span class="string">&quot;因为墨是煤的一家。墨是用煤烟制成的。煤是永远也洗不白的，因此，墨写的字、画的画是不褪色的.&quot;</span></span></span><br><span class="line"><span class="javascript">          &#125;,</span></span><br><span class="line"><span class="javascript">          &#123;</span></span><br><span class="line"><span class="javascript">            <span class="attr">id</span>: <span class="number">202003</span>,</span></span><br><span class="line"><span class="javascript">            <span class="attr">question</span>: <span class="string">&quot;为什么海洋是蓝色的？?&quot;</span>,</span></span><br><span class="line"><span class="javascript">            <span class="attr">answer</span>: <span class="string">&quot;大海看起来是那么蓝，那么美。可实际上，海水也是无色透明的.&quot;</span></span></span><br><span class="line"><span class="javascript">          &#125;,</span></span><br><span class="line"><span class="javascript">        ]</span></span><br><span class="line"><span class="javascript">      &#125;;</span></span><br><span class="line"><span class="javascript">    &#125;,</span></span><br><span class="line"><span class="javascript">  &#125;;</span></span><br><span class="line"><span class="javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure></li>
</ul>
<hr>
<h4 id="（4）懒加载"><a href="#（4）懒加载" class="headerlink" title="（4）懒加载"></a>（4）懒加载</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> Vue <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span></span><br><span class="line"><span class="keyword">import</span> VueRouter <span class="keyword">from</span> <span class="string">&#x27;vue-router&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// import Home from &#x27;../views/Home.vue&#x27;</span></span><br><span class="line"><span class="comment">// import About from &#x27;../views/About.vue&#x27;</span></span><br><span class="line"><span class="comment">// import Learn from &#x27;../views/Learn.vue&#x27;</span></span><br><span class="line"><span class="comment">// import Student from &#x27;../views/Student.vue&#x27;</span></span><br><span class="line"><span class="comment">// import Community from &#x27;../views/Community.vue&#x27;</span></span><br><span class="line"><span class="comment">// import Question from &#x27;../components/community/question&#x27;</span></span><br><span class="line"><span class="comment">// import Forum from &#x27;../components/community/forum&#x27;</span></span><br><span class="line"><span class="comment">// import Help from &#x27;../components/community/help&#x27;</span></span><br><span class="line"><span class="comment">// import Answer from &#x27;../components/Answer&#x27;</span></span><br><span class="line"><span class="comment">// import Error404 from &#x27;../components/Error&#x27;</span></span><br><span class="line"><span class="comment">// import User from &#x27;../components/community/user&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> Home = <span class="function">() =&gt;</span> <span class="keyword">import</span>( <span class="string">&#x27;../views/Home.vue&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> About = <span class="function">() =&gt;</span> <span class="keyword">import</span>( <span class="string">&#x27;../views/About.vue&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> Learn = <span class="function">() =&gt;</span> <span class="keyword">import</span>( <span class="string">&#x27;../views/Learn.vue&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> Student = <span class="function">() =&gt;</span> <span class="keyword">import</span>( <span class="string">&#x27;../views/Student.vue&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> Community = <span class="function">() =&gt;</span> <span class="keyword">import</span>( <span class="string">&#x27;../views/Community.vue&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> Question = <span class="function">() =&gt;</span> <span class="keyword">import</span>( <span class="string">&#x27;../components/community/question&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> Forum = <span class="function">() =&gt;</span> <span class="keyword">import</span>( <span class="string">&#x27;../components/community/forum&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> Help = <span class="function">() =&gt;</span> <span class="keyword">import</span>( <span class="string">&#x27;../components/community/help&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> Answer = <span class="function">() =&gt;</span> <span class="keyword">import</span>( <span class="string">&#x27;../components/Answer&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> Error404 = <span class="function">() =&gt;</span> <span class="keyword">import</span>( <span class="string">&#x27;../components/Error&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> User = <span class="function">() =&gt;</span> <span class="keyword">import</span>( <span class="string">&#x27;../components/community/user&#x27;</span>);</span><br></pre></td></tr></table></figure>
<hr>
<h3 id="3-状态vuex"><a href="#3-状态vuex" class="headerlink" title="3.状态vuex"></a>3.状态vuex</h3><h4 id="（1）非父子组件传值"><a href="#（1）非父子组件传值" class="headerlink" title="（1）非父子组件传值"></a>（1）非父子组件传值</h4><ul>
<li>依赖共同祖先组件传值<ul>
<li>两个组件的关系太远，嵌套太深，数据太多不适用</li>
<li>一个组件给多个组件传值，关系复杂不适用</li>
</ul>
</li>
</ul>
<ul>
<li>事件总线<ul>
<li>利用Vue的prototype公共属性进行事件绑定与监听</li>
<li>需要依赖于事件</li>
</ul>
</li>
</ul>
<h4 id="（2）vuex-Store"><a href="#（2）vuex-Store" class="headerlink" title="（2）vuex.Store"></a>（2）vuex.Store</h4><ul>
<li>$store.state</li>
<li>$store.getters</li>
<li>mapState</li>
<li>mapGetters</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> Vue <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span></span><br><span class="line"><span class="keyword">import</span> Vuex <span class="keyword">from</span> <span class="string">&#x27;vuex&#x27;</span></span><br><span class="line"></span><br><span class="line">Vue.use(Vuex)</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">new</span> Vuex.Store(&#123;</span><br><span class="line">  <span class="attr">state</span>: &#123;<span class="comment">//公共数据池</span></span><br><span class="line">    <span class="attr">studentList</span>: []</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">getters</span>: &#123;</span><br><span class="line">    <span class="function"><span class="title">list</span>(<span class="params">state, getters</span>)</span>&#123;<span class="comment">//数据池、自身</span></span><br><span class="line">      <span class="keyword">return</span> state.studentList.map(<span class="function">(<span class="params">item, index</span>) =&gt;</span> &#123;</span><br><span class="line">        <span class="keyword">if</span>(index &lt; <span class="number">3</span>)&#123;</span><br><span class="line">          <span class="keyword">return</span> getters.prefix + item;</span><br><span class="line">        &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">          <span class="keyword">return</span> item + getters.suffix;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;)</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="function"><span class="title">prefix</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="string">&quot;#_&quot;</span></span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="function"><span class="title">suffix</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="string">&quot;-$&quot;</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">mutations</span>: &#123;<span class="comment">//同步处理</span></span><br><span class="line">    <span class="function"><span class="title">changeStudentList</span>(<span class="params">state, val</span>)</span>&#123;</span><br><span class="line">      state.studentList.push(val)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">actions</span>: &#123;<span class="comment">//异步处理</span></span><br><span class="line">    <span class="function"><span class="title">change</span>(<span class="params">ctx, val</span>)</span>&#123;</span><br><span class="line">      <span class="built_in">setTimeout</span>(<span class="function">()=&gt;</span>&#123;</span><br><span class="line">        ctx.commit(<span class="string">&quot;changeStudentList&quot;</span>, val)</span><br><span class="line">      &#125;, <span class="number">1000</span>)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">modules</span>: &#123;<span class="comment">//模块，将每一组页面下的数据单独抽离成一个模块，便于维护</span></span><br><span class="line">    <span class="attr">student</span>: &#123;</span><br><span class="line">      <span class="attr">namespaced</span>: <span class="literal">true</span>,<span class="comment">//命名空间</span></span><br><span class="line">      state,</span><br><span class="line">      getters,</span><br><span class="line">      ...</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="attr">product</span>: &#123;</span><br><span class="line">      ...</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">template</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- &lt;div&gt;</span></span><br><span class="line"><span class="comment">      &lt;p v-if=&quot;list.length !== 0&quot;&gt;学员列表：&lt;/p&gt;</span></span><br><span class="line"><span class="comment">      &lt;ul&gt;</span></span><br><span class="line"><span class="comment">        &lt;li v-for=&quot;(item, index) in list&quot; :key=&quot;item+index&quot;&gt;&#123;&#123;index+1&#125;&#125;.&#123;&#123;item&#125;&#125;&lt;/li&gt;</span></span><br><span class="line"><span class="comment">      &lt;/ul&gt;</span></span><br><span class="line"><span class="comment">    &lt;/div&gt; --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">p</span> <span class="attr">v-if</span>=<span class="string">&quot;list.length !== 0&quot;</span>&gt;</span>学员列表：<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">ul</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">li</span> <span class="attr">v-for</span>=<span class="string">&quot;(item, index) in list&quot;</span> <span class="attr">:key</span>=<span class="string">&quot;item+index&quot;</span>&gt;</span>&#123;&#123;index+1&#125;&#125;.&#123;&#123;item&#125;&#125;<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">ul</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">ul</span> <span class="attr">class</span>=<span class="string">&quot;new&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">li</span> <span class="attr">v-for</span>=<span class="string">&quot;(item, index) in newList&quot;</span> <span class="attr">:key</span>=<span class="string">&quot;item+index&quot;</span>&gt;</span>&#123;&#123;index+1&#125;&#125;.&#123;&#123;item&#125;&#125;<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">ul</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">template</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="javascript"></span></span><br><span class="line"><span class="javascript"></span></span><br><span class="line"><span class="javascript">  <span class="keyword">import</span> &#123;mapState, mapGetters&#125; <span class="keyword">from</span> <span class="string">&#x27;vuex&#x27;</span>;</span></span><br><span class="line"><span class="javascript"></span></span><br><span class="line"><span class="javascript">   <span class="keyword">export</span> <span class="keyword">default</span> &#123;</span></span><br><span class="line"><span class="javascript">       <span class="function"><span class="title">data</span>(<span class="params"></span>)</span> &#123;</span></span><br><span class="line"><span class="javascript">           <span class="keyword">return</span> &#123;</span></span><br><span class="line"><span class="javascript">            <span class="comment">// studentList: this.$store.state.studentList</span></span></span><br><span class="line"><span class="javascript">           &#125;;</span></span><br><span class="line"><span class="javascript">       &#125;,</span></span><br><span class="line"><span class="javascript">       <span class="attr">computed</span>: &#123;</span></span><br><span class="line"><span class="javascript">        ...mapState(&#123;<span class="comment">//重命名</span></span></span><br><span class="line"><span class="javascript">          <span class="attr">list</span>: <span class="function"><span class="params">state</span> =&gt;</span> state.studentList</span></span><br><span class="line"><span class="javascript">        &#125;),</span></span><br><span class="line"><span class="javascript">        ...mapState(<span class="string">&quot;modelName&quot;</span>, [<span class="string">&#x27;studentList&#x27;</span>])<span class="comment">//使用模块需要添加对应模块名</span></span></span><br><span class="line"><span class="javascript">        ...mapGetters(&#123;<span class="comment">//重命名</span></span></span><br><span class="line"><span class="javascript">          <span class="attr">newList</span>: <span class="string">&#x27;list&#x27;</span></span></span><br><span class="line"><span class="javascript">        &#125;)</span></span><br><span class="line"><span class="javascript">       &#125;,</span></span><br><span class="line"><span class="javascript">       <span class="function"><span class="title">created</span>(<span class="params"></span>)</span>&#123;</span></span><br><span class="line"><span class="javascript">        <span class="comment">//  this.bus.$on(&quot;new-student&quot;, list =&gt; &#123;</span></span></span><br><span class="line"><span class="javascript">        <span class="comment">//    this.studentList = list;</span></span></span><br><span class="line"><span class="javascript">        <span class="comment">//  &#125;)</span></span></span><br><span class="line"><span class="javascript">       &#125;</span></span><br><span class="line"><span class="javascript">   &#125;;</span></span><br><span class="line"><span class="javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">template</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">span</span>&gt;</span>添加学员：<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> <span class="attr">v-model</span>=<span class="string">&quot;studentName&quot;</span>&gt;</span></span><br><span class="line">      <span class="comment">&lt;!-- &lt;button @click=&quot;addStudent&quot;&gt;添加&lt;/button&gt; --&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">button</span> @<span class="attr">click</span>=<span class="string">&quot;[change(studentName), reset()]&quot;</span>&gt;</span>添加<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">template</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="javascript"></span></span><br><span class="line"><span class="javascript">  <span class="keyword">import</span> &#123;mapActions&#125; <span class="keyword">from</span> <span class="string">&#x27;vuex&#x27;</span>;<span class="comment">//简洁操作</span></span></span><br><span class="line"><span class="javascript"></span></span><br><span class="line"><span class="javascript">   <span class="keyword">export</span> <span class="keyword">default</span> &#123;</span></span><br><span class="line"><span class="javascript">       <span class="function"><span class="title">data</span>(<span class="params"></span>)</span> &#123;</span></span><br><span class="line"><span class="javascript">           <span class="keyword">return</span> &#123;</span></span><br><span class="line"><span class="javascript">            <span class="attr">studentName</span>: <span class="string">&quot;&quot;</span>,</span></span><br><span class="line"><span class="javascript">            <span class="comment">// studentList:[]</span></span></span><br><span class="line"><span class="javascript">           &#125;;</span></span><br><span class="line"><span class="javascript">       &#125;,</span></span><br><span class="line"><span class="javascript">       <span class="attr">methods</span>: &#123;</span></span><br><span class="line"><span class="javascript">         ...mapActions([<span class="string">&#x27;change&#x27;</span>]),</span></span><br><span class="line"><span class="javascript">         <span class="function"><span class="title">addStudent</span>(<span class="params"></span>)</span>&#123;</span></span><br><span class="line"><span class="javascript">          <span class="built_in">this</span>.studentList.push(<span class="built_in">this</span>.studentName);</span></span><br><span class="line"><span class="javascript">          <span class="built_in">this</span>.bus.$emit(<span class="string">&quot;new-student&quot;</span>, <span class="built_in">this</span>.studentList);</span></span><br><span class="line"><span class="javascript"></span></span><br><span class="line"><span class="javascript">          <span class="built_in">this</span>.$store.state.studentList.push(<span class="built_in">this</span>.studentName);<span class="comment">//手动触发，不适用严格模式</span></span></span><br><span class="line"><span class="javascript">          <span class="built_in">this</span>.$store.commit(<span class="string">&quot;changeStudentList&quot;</span>, <span class="built_in">this</span>.studentName);<span class="comment">//同步更改</span></span></span><br><span class="line"><span class="javascript">          <span class="built_in">this</span>.$store.commit(<span class="string">&quot;modelName/changeStudentList&quot;</span>, <span class="built_in">this</span>.studentName);<span class="comment">//同步更改(使用模块)</span></span></span><br><span class="line"><span class="javascript">          <span class="built_in">this</span>.$store.dispatch(<span class="string">&quot;change&quot;</span>, <span class="built_in">this</span>.studentName)<span class="comment">//异步更改</span></span></span><br><span class="line"><span class="javascript">          </span></span><br><span class="line"><span class="javascript">         &#125;,</span></span><br><span class="line"><span class="javascript">         <span class="function"><span class="title">reset</span>(<span class="params"></span>)</span>&#123;</span></span><br><span class="line"><span class="javascript">          <span class="built_in">this</span>.studentName = <span class="string">&quot;&quot;</span>;</span></span><br><span class="line"><span class="javascript">         &#125;</span></span><br><span class="line"><span class="javascript">       &#125;</span></span><br><span class="line"><span class="javascript">   &#125;;</span></span><br><span class="line"><span class="javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>
      
      <!-- 打赏 -->
      
    </div>
    <footer class="article-footer">
      <a data-url="https://gitee.com/huafu123/blog/2018/08/01/VUEa/" data-id="ckya9fc19000tygf697f2bows"
        class="article-share-link">分享</a>
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/blog/tags/js-vue/" rel="tag">js vue</a></li></ul>

    </footer>

  </div>

  

  
  
  

  

</article>
    
    <article id="post-GULPa" class="article article-type-post" itemscope
  itemprop="blogPost" data-scroll-reveal>

  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/blog/2018/07/21/GULPa/"
    >Gulp 初识</a
  >
</h2>
  

    </header>
    

    
    <div class="article-meta">
      <a href="/blog/2018/07/21/GULPa/" class="article-date">
  <time datetime="2018-07-20T16:00:00.000Z" itemprop="datePublished">2018-07-21</time>
</a>
      
    </div>
    

    

    <div class="article-entry" itemprop="articleBody">
      


      

      
      <h1 id="gulp概述"><a href="#gulp概述" class="headerlink" title="gulp概述"></a>gulp概述</h1><h2 id="（一）环境配置"><a href="#（一）环境配置" class="headerlink" title="（一）环境配置"></a>（一）环境配置</h2><ol>
<li>npm i -g gulp</li>
<li>npm init -y</li>
<li>npm i -D gulp</li>
<li>create gulpfile.js</li>
</ol>
<h2 id="（二）gulpfile-js"><a href="#（二）gulpfile-js" class="headerlink" title="（二）gulpfile.js"></a>（二）gulpfile.js</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> gulp = <span class="built_in">require</span>(<span class="string">&quot;gulp&quot;</span>); <span class="comment">//gulp4.0</span></span><br><span class="line"><span class="keyword">const</span> minifyHtml = <span class="built_in">require</span>(<span class="string">&quot;gulp-minify-html&quot;</span>); <span class="comment">//压缩html</span></span><br><span class="line"><span class="keyword">const</span> imagemin = <span class="built_in">require</span>(<span class="string">&#x27;gulp-imagemin&#x27;</span>);<span class="comment">//图片压缩</span></span><br><span class="line"><span class="keyword">const</span> minifyCss = <span class="built_in">require</span>(<span class="string">&quot;gulp-minify-css&quot;</span>); <span class="comment">//压缩CSS</span></span><br><span class="line"><span class="keyword">const</span> less = <span class="built_in">require</span>(<span class="string">&#x27;gulp-less&#x27;</span>); <span class="comment">//编译less</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> postcss = <span class="built_in">require</span>(<span class="string">&quot;gulp-postcss&quot;</span>);<span class="comment">//自动添加css3前缀</span></span><br><span class="line"><span class="keyword">const</span> autoprefixer = <span class="built_in">require</span>(<span class="string">&quot;autoprefixer&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> uglify = <span class="built_in">require</span>(<span class="string">&#x27;gulp-uglify&#x27;</span>); <span class="comment">//js压缩</span></span><br><span class="line"><span class="keyword">const</span> debug = <span class="built_in">require</span>(<span class="string">&quot;gulp-strip-debug&quot;</span>);<span class="comment">//清除js调试语句</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> connect = <span class="built_in">require</span>(<span class="string">&quot;gulp-connect&quot;</span>);<span class="comment">//服务器依赖</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//出入口路径</span></span><br><span class="line"><span class="keyword">const</span> folder = &#123;</span><br><span class="line">  <span class="attr">src</span>: <span class="string">&quot;src/&quot;</span>,</span><br><span class="line">  <span class="attr">dist</span>: <span class="string">&quot;dist/&quot;</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//任务队列</span></span><br><span class="line"><span class="keyword">const</span> taskArr = [];</span><br><span class="line"></span><br><span class="line"><span class="comment">//html任务</span></span><br><span class="line">gulp.task(<span class="string">&quot;html&quot;</span>, <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">  gulp.src(folder.src + <span class="string">&quot;html/*&quot;</span>)</span><br><span class="line">      .pipe(connect.reload())</span><br><span class="line">      .pipe(minifyHtml())</span><br><span class="line">      .pipe(gulp.dest(folder.dist + <span class="string">&quot;html/&quot;</span>))</span><br><span class="line">&#125;)</span><br><span class="line">taskArr.push(<span class="string">&quot;html&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">//css任务</span></span><br><span class="line">gulp.task(<span class="string">&quot;css&quot;</span>, <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">  gulp.src(folder.src + <span class="string">&quot;css/*&quot;</span>)</span><br><span class="line">      .pipe(connect.reload())</span><br><span class="line">      .pipe(less())</span><br><span class="line">      .pipe(postcss([autoprefixer()]))</span><br><span class="line">      .pipe(minifyCss())</span><br><span class="line">      .pipe(gulp.dest(folder.dist + <span class="string">&quot;css/&quot;</span>))</span><br><span class="line">&#125;)</span><br><span class="line">taskArr.push(<span class="string">&quot;css&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">//image任务</span></span><br><span class="line">gulp.task(<span class="string">&quot;image&quot;</span>, <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">  gulp.src(folder.src + <span class="string">&quot;image/*&quot;</span>)</span><br><span class="line">      .pipe(imagemin())</span><br><span class="line">      .pipe(gulp.dest(folder.dist + <span class="string">&quot;image/&quot;</span>))</span><br><span class="line">&#125;)</span><br><span class="line">taskArr.push(<span class="string">&quot;image&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">//js任务</span></span><br><span class="line">gulp.task(<span class="string">&quot;js&quot;</span>, <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">  gulp.src(folder.src + <span class="string">&quot;js/*&quot;</span>)</span><br><span class="line">      .pipe(connect.reload())</span><br><span class="line">      .pipe(debug())</span><br><span class="line">      .pipe(uglify())</span><br><span class="line">      .pipe(gulp.dest(folder.dist + <span class="string">&quot;js/&quot;</span>))</span><br><span class="line">&#125;)</span><br><span class="line">taskArr.push(<span class="string">&quot;js&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">//服务器任务</span></span><br><span class="line">gulp.task(<span class="string">&quot;server&quot;</span>, <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">  connect.server(&#123;</span><br><span class="line">    <span class="attr">port</span>: <span class="number">9000</span>,<span class="comment">//端口</span></span><br><span class="line">    <span class="attr">livereload</span>:<span class="literal">true</span><span class="comment">//刷新</span></span><br><span class="line">  &#125;);</span><br><span class="line">&#125;)</span><br><span class="line">taskArr.push(<span class="string">&quot;server&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">//监听任务</span></span><br><span class="line">gulp.task(<span class="string">&quot;watch&quot;</span>, <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">  gulp.watch(folder.src + <span class="string">&quot;html/*&quot;</span>, gulp.series(<span class="string">&quot;html&quot;</span>));</span><br><span class="line">  gulp.watch(folder.src + <span class="string">&quot;css/*&quot;</span>, gulp.series(<span class="string">&quot;css&quot;</span>));</span><br><span class="line">  gulp.watch(folder.src + <span class="string">&quot;js/*&quot;</span>, gulp.series(<span class="string">&quot;js&quot;</span>));</span><br><span class="line">&#125;)</span><br><span class="line">taskArr.push(<span class="string">&quot;watch&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">//默认执行任务队列</span></span><br><span class="line">gulp.task(<span class="string">&quot;default&quot;</span>, gulp.parallel(taskArr)) </span><br></pre></td></tr></table></figure>

      
      <!-- 打赏 -->
      
    </div>
    <footer class="article-footer">
      <a data-url="https://gitee.com/huafu123/blog/2018/07/21/GULPa/" data-id="ckya9fc10000dygf6c1pu03vl"
        class="article-share-link">分享</a>
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/blog/tags/gulp/" rel="tag">gulp</a></li></ul>

    </footer>

  </div>

  

  
  
  

  

</article>
    
    <article id="post-WEBPACKa" class="article article-type-post" itemscope
  itemprop="blogPost" data-scroll-reveal>

  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/blog/2018/07/11/WEBPACKa/"
    >Webpack 初识</a
  >
</h2>
  

    </header>
    

    
    <div class="article-meta">
      <a href="/blog/2018/07/11/WEBPACKa/" class="article-date">
  <time datetime="2018-07-10T16:00:00.000Z" itemprop="datePublished">2018-07-11</time>
</a>
      
    </div>
    

    

    <div class="article-entry" itemprop="articleBody">
      


      

      
      <h1 id="一、模块化"><a href="#一、模块化" class="headerlink" title="一、模块化"></a>一、模块化</h1><h2 id="（一）工程化思想"><a href="#（一）工程化思想" class="headerlink" title="（一）工程化思想"></a>（一）工程化思想</h2><ul>
<li>前端工程化是根据业务特点，将前端开发流程规范化，标准化，它包括了开发流程，技术选型，代码规范，构建发布等，用于提升前端工程师的开发效率和代码质量。</li>
</ul>
<h2 id="（二）js-模块化"><a href="#（二）js-模块化" class="headerlink" title="（二）js 模块化"></a>（二）js 模块化</h2><h3 id="1-commonJS规范"><a href="#1-commonJS规范" class="headerlink" title="1.commonJS规范"></a>1.commonJS规范</h3><h4 id="（1）核心思想"><a href="#（1）核心思想" class="headerlink" title="（1）核心思想"></a>（1）核心思想</h4><ul>
<li>1）据 CommonJs 规范规定每一个 Js 文件都可以看作一个模块，其内部定义的变量是属于这个模块的，不会对外暴露，也就是说不会污染全局变量。该规范最初用在服务器端的 node 环境中。</li>
<li>2）CommonJS 采用==同步加载==不同模块文件，适用于服务器端的。因为模块文件都存放在服务器的各个硬盘上，读取加载时间快，适合服务器端，不适应浏览器。</li>
<li>3）浏览器不兼容 CommonJs，原因是浏览器缺少 module、exports、require、global 四个环境变量。如要使用需要工具转换。</li>
<li>4）CommonJS 的核心思想就是通过 require 方法来同步加载所要依赖的其他模块，然后通过 exports 或者 module.exports 来导出需要暴露的接口。</li>
</ul>
<h4 id="（2）使用"><a href="#（2）使用" class="headerlink" title="（2）使用"></a>（2）使用</h4><ul>
<li><p>暴露接口方式</p>
<ul>
<li>module.exports = value；</li>
<li>exports.XXX = value；</li>
</ul>
</li>
<li><p>exports 本质是一个空对象。</p>
</li>
<li><p>引入模块 require(XXX)</p>
</li>
</ul>
<h4 id="（3）commonJs-兼容浏览器"><a href="#（3）commonJs-兼容浏览器" class="headerlink" title="（3）commonJs 兼容浏览器"></a>（3）commonJs 兼容浏览器</h4><ul>
<li>install browserify</li>
<li>browserify a.js -o bundle.js</li>
</ul>
<hr>
<h3 id="2-AMD-规范"><a href="#2-AMD-规范" class="headerlink" title="2.AMD 规范"></a>2.AMD 规范</h3><h4 id="（1）核心思想-1"><a href="#（1）核心思想-1" class="headerlink" title="（1）核心思想"></a>（1）核心思想</h4><ul>
<li>1）CommonJs 为服务器端而生，采用的同步加载方式。因此不适用浏览器。因为浏览器需要到服务器加载文件，请求时间远大于本机读取的时间，倘若文件较多，网络迟缓就会导致页面瘫痪，所以浏览器更希望能够时间异步加载的方式。</li>
<li>2）AMD 规范则是异步加载模块，允许指定回调函数。等模块异步加载完成后即可调用回调函数。</li>
<li>3）AMD 得意的产出就是 require.js</li>
<li>4）AMD 的核心思想就是通过 define 来定义一个模块，然后使用 require 来加载一个模块。</li>
<li>5）==依赖前置，需提前加载依赖，贪婪加载==</li>
</ul>
<h4 id="（2）使用-1"><a href="#（2）使用-1" class="headerlink" title="（2）使用"></a>（2）使用</h4><ul>
<li>AMD 规范的使用依赖于 require.js <a target="_blank" rel="noopener" href="https://requirejs.org/">https://requirejs.org/</a></li>
<li>script 标签的 src 属性引入依赖文件 require.js</li>
<li>script 标签的 src 属性引入入口文件 index.js</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">&lt;script src=<span class="string">&quot;./require.js&quot;</span> data-main=<span class="string">&quot;./index.js&quot;</span>&gt;&lt;/script&gt;;</span><br><span class="line"></span><br><span class="line">define([<span class="string">&quot;m1&quot;</span>], <span class="function"><span class="keyword">function</span>(<span class="params">m1</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> msg = <span class="string">&quot;m2-amd&quot;</span>;</span><br><span class="line">  <span class="function"><span class="keyword">function</span> <span class="title">show</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(msg, m1.getName());</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> &#123; show &#125;;</span><br><span class="line">&#125;)(<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="built_in">require</span>.config(&#123;</span><br><span class="line">    <span class="attr">paths</span>: &#123;</span><br><span class="line">      <span class="attr">m1</span>: <span class="string">&quot;./module/m1&quot;</span>,</span><br><span class="line">      <span class="attr">m2</span>: <span class="string">&quot;./module/m2&quot;</span>,</span><br><span class="line">      <span class="attr">jquery</span>: <span class="string">&quot;./libs/jquery.min&quot;</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;);</span><br><span class="line"></span><br><span class="line">  <span class="built_in">require</span>([<span class="string">&quot;m2&quot;</span>, <span class="string">&quot;jquery&quot;</span>], <span class="function"><span class="keyword">function</span>(<span class="params">m2, $</span>) </span>&#123;</span><br><span class="line">    m2.show();</span><br><span class="line">    $(<span class="string">&quot;.demo&quot;</span>).css(<span class="string">&quot;color&quot;</span>, <span class="string">&quot;red&quot;</span>);</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;)();</span><br></pre></td></tr></table></figure>

<hr>
<h3 id="3-CMD-规范"><a href="#3-CMD-规范" class="headerlink" title="3.CMD 规范"></a>3.CMD 规范</h3><h4 id="（1）核心思想-2"><a href="#（1）核心思想-2" class="headerlink" title="（1）核心思想"></a>（1）核心思想</h4><ul>
<li>1）CMD 异步加载，跟 AMD 的主要区别在于，AMD 依赖前置，提前加载依赖。而 CMD 就近加载，按需加载。</li>
<li>2）产物 seaJs，跟 requireJs 使用有些相似。</li>
<li>3）CMD 的核心思想就是通过 define 来定义一个模块，然后使用 require 来加载一个模块。</li>
<li>4）==依赖就近加载，按需加载==</li>
</ul>
<h4 id="（2）使用-2"><a href="#（2）使用-2" class="headerlink" title="（2）使用"></a>（2）使用</h4><ul>
<li>script 标签引入依赖文件 sea.js</li>
<li>执行入口文件 seajs.use(index.js)</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line">&lt;script src=<span class="string">&quot;./sea.js&quot;</span>&gt;&lt;/script&gt;</span><br><span class="line"><span class="xml"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="javascript"></span></span></span><br><span class="line"><span class="javascript"><span class="xml">  seajs.use(<span class="string">&quot;./index.js&quot;</span>)</span></span></span><br><span class="line"><span class="javascript"><span class="xml"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span></span><br><span class="line"></span><br><span class="line">define(<span class="function"><span class="keyword">function</span> (<span class="params"><span class="built_in">require</span>, <span class="built_in">exports</span>, <span class="built_in">module</span></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> name = <span class="string">&quot;m4-cmd&quot;</span>;</span><br><span class="line">  <span class="comment">//同步加载</span></span><br><span class="line">  <span class="keyword">var</span> m1 = <span class="built_in">require</span>(<span class="string">&quot;./m1&quot;</span>)</span><br><span class="line">  m1.showName();</span><br><span class="line">  <span class="comment">//异步加载</span></span><br><span class="line">  <span class="built_in">require</span>.async(<span class="string">&#x27;./m2&#x27;</span>, <span class="function"><span class="keyword">function</span>(<span class="params">m2</span>)</span>&#123;</span><br><span class="line">    m2();</span><br><span class="line">  &#125;)</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">function</span> <span class="title">showName</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(name);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="built_in">exports</span>.showName = showName;</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">define(<span class="function"><span class="keyword">function</span> (<span class="params"><span class="built_in">require</span>, <span class="built_in">exports</span>, <span class="built_in">module</span></span>) </span>&#123;</span><br><span class="line">  <span class="comment">//同步加载</span></span><br><span class="line">  <span class="keyword">var</span> m4 = <span class="built_in">require</span>(<span class="string">&quot;./module/m4&quot;</span>)</span><br><span class="line">  m4.showName();</span><br><span class="line">  <span class="comment">//异步加载</span></span><br><span class="line">  <span class="built_in">require</span>.async(<span class="string">&#x27;./module/m3&#x27;</span>, <span class="function"><span class="keyword">function</span>(<span class="params">m3</span>)</span>&#123;</span><br><span class="line">    m3.showName();</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<hr>
<h3 id="4-ES-Modules-规范"><a href="#4-ES-Modules-规范" class="headerlink" title="4.ES Modules 规范"></a>4.ES Modules 规范</h3><h4 id="（1）核心思想-3"><a href="#（1）核心思想-3" class="headerlink" title="（1）核心思想"></a>（1）核心思想</h4><ul>
<li>ES6 自带模块化，可以使用 import 关键字引入模块，通过 export 关键字导出模块，功能较之于前几个方案更为强大，也是我们所推崇的，但是由于 ES6 目前无法在浏览器中执行，所以，我们只能通过 babel 将不被支持的 import 编译为当前受到广泛支持的 require。</li>
</ul>
<h4 id="（2）模块化-what？"><a href="#（2）模块化-what？" class="headerlink" title="（2）模块化 what？"></a>（2）模块化 what？</h4><ul>
<li>模块化是指将一个复杂的系统分解为多个模块，方便编码。</li>
</ul>
<h4 id="（3）模块化-why？"><a href="#（3）模块化-why？" class="headerlink" title="（3）模块化 why？"></a>（3）模块化 why？</h4><ul>
<li>降低复杂性，降低代码耦合度，部署方便，提高效率。</li>
</ul>
<h4 id="（4）模块化好处？"><a href="#（4）模块化好处？" class="headerlink" title="（4）模块化好处？"></a>（4）模块化好处？</h4><ul>
<li>a,避免命名冲突，减少变量空间污染</li>
<li>b,更好的分离代码，按需加载</li>
<li>c,更高复用性</li>
<li>d,更高可维护性</li>
</ul>
<hr>
<h2 id="（三）预处理-Less"><a href="#（三）预处理-Less" class="headerlink" title="（三）预处理 Less"></a>（三）预处理 Less</h2><h3 id="1-嵌套"><a href="#1-嵌套" class="headerlink" title="1.嵌套"></a>1.嵌套</h3><h3 id="2-注释"><a href="#2-注释" class="headerlink" title="2.注释"></a>2.注释</h3><ul>
<li>单行注释：只希望被开发人员看到，不会编译进文件</li>
<li>包裹注释：希望用于代码阅读，会编译进文件</li>
</ul>
<h3 id="3-变量-变量运算-变量作用域"><a href="#3-变量-变量运算-变量作用域" class="headerlink" title="3.变量 / 变量运算 / 变量作用域"></a>3.变量 / 变量运算 / 变量作用域</h3><h3 id="4-混合-默认值-匹配-导入"><a href="#4-混合-默认值-匹配-导入" class="headerlink" title="4.混合 / 默认值 / 匹配 / 导入"></a>4.混合 / 默认值 / 匹配 / 导入</h3><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">@width:</span> <span class="number">500px</span>; <span class="comment">//变量</span></span><br><span class="line"><span class="variable">@height:</span> <span class="variable">@width</span> + <span class="number">100px</span>; <span class="comment">//变量运算</span></span><br><span class="line"><span class="variable">@color:</span> pink;</span><br><span class="line"></span><br><span class="line"><span class="comment">//混合</span></span><br><span class="line"><span class="selector-class">.border</span>(<span class="variable">@w</span>, <span class="variable">@s</span>, <span class="variable">@c</span>) &#123;</span><br><span class="line">  <span class="attribute">border</span>: <span class="variable">@w</span> <span class="variable">@s</span> <span class="variable">@c</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//默认值</span></span><br><span class="line"><span class="selector-class">.center</span>(<span class="variable">@top</span>: <span class="number">0px</span>) &#123;</span><br><span class="line">  <span class="attribute">margin</span>: <span class="variable">@top</span> auto;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//导入</span></span><br><span class="line"><span class="keyword">@import</span> <span class="string">&quot;./trangle&quot;</span>;</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.wrapper</span> &#123;</span><br><span class="line">  <span class="attribute">width</span>: <span class="variable">@width</span>;</span><br><span class="line">  <span class="attribute">height</span>: <span class="variable">@height</span>;</span><br><span class="line">  <span class="attribute">background-color</span>: <span class="variable">@color</span>;</span><br><span class="line">  <span class="selector-class">.center</span>;</span><br><span class="line">  <span class="selector-class">.demo</span> &#123;</span><br><span class="line">    <span class="attribute">width</span>: <span class="number">100px</span>;</span><br><span class="line">    <span class="attribute">height</span>: <span class="number">100px</span>;</span><br><span class="line">    <span class="selector-class">.border</span>(<span class="number">5px</span>, solid, black);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="selector-class">.box</span> &#123;</span><br><span class="line">    <span class="selector-class">.trangle</span>(T, <span class="number">50px</span>, blue) <span class="comment">//匹配;</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<hr>
<h1 id="二、基于模块化打包Webpack"><a href="#二、基于模块化打包Webpack" class="headerlink" title="二、基于模块化打包Webpack"></a>二、基于模块化打包Webpack</h1><h2 id="（一）环境配置（4-0-版本）"><a href="#（一）环境配置（4-0-版本）" class="headerlink" title="（一）环境配置（4.0 版本）"></a>（一）环境配置（4.0 版本）</h2><blockquote>
<p>安装node<br>npm install webpack webpack-cli -g<br>npm init -y<br>npm install webpack webpack-cli -D<br>npm install<br>webpack</p>
</blockquote>
<ul>
<li>安装全局的webpack</li>
<li>初始化项目（默认生成package.json文件）</li>
<li>安装项目的webpack</li>
<li>初始化依赖（默认根据package.json中”devDependencies”的配置依次加载依赖，在安装依赖的时候可以用 –save-dev（-D）命令将依赖记录于配置中）</li>
<li>执行webpack 打包（基于没有 webpack.config.js）默认入口：src/index.js 默认出口：dist/main.js</li>
</ul>
<h2 id="（二）webpack-config-js-配置"><a href="#（二）webpack-config-js-配置" class="headerlink" title="（二）webpack.config.js 配置"></a>（二）webpack.config.js 配置</h2><h3 id="1-entry"><a href="#1-entry" class="headerlink" title="1.entry"></a>1.entry</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  <span class="comment">//单入口</span></span><br><span class="line">  <span class="attr">entry</span>: <span class="string">&quot;path&quot;</span></span><br><span class="line">  <span class="comment">//多入口</span></span><br><span class="line">  <span class="attr">entry</span>: &#123;</span><br><span class="line">    <span class="attr">page1</span>: <span class="string">&quot;path&quot;</span>,</span><br><span class="line">    <span class="attr">page2</span>: <span class="string">&quot;path&quot;</span>,</span><br><span class="line">    <span class="attr">page3</span>: <span class="string">&quot;path&quot;</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<hr>
<h3 id="2-output"><a href="#2-output" class="headerlink" title="2.output"></a>2.output</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">&quot;path);</span></span><br><span class="line"><span class="string">module.exports = &#123;</span></span><br><span class="line"><span class="string">  //单出口</span></span><br><span class="line"><span class="string">  output: &#123;</span></span><br><span class="line"><span class="string">    filename: &quot;</span>index.js<span class="string">&quot;,</span></span><br><span class="line"><span class="string">    path: path.resolve(__dirname + &quot;</span>/dist<span class="string">&quot;);</span></span><br><span class="line"><span class="string">  &#125;</span></span><br><span class="line"><span class="string">  //多入口</span></span><br><span class="line"><span class="string">  output: &#123;</span></span><br><span class="line"><span class="string">    filename: &quot;</span>[name].js<span class="string">&quot;,//使用模块名</span></span><br><span class="line"><span class="string">    filename: &quot;</span>[id].js<span class="string">&quot;,//使用模块id</span></span><br><span class="line"><span class="string">    filename: &quot;</span>[name][hash:<span class="number">20</span>].js<span class="string">&quot;,//加入hash</span></span><br><span class="line"><span class="string">    filename: &quot;</span>[chunkhash].js<span class="string">&quot;,//chunk内容的hash</span></span><br><span class="line"><span class="string">    path: path.resolve(__dirname + &quot;</span>/dist<span class="string">&quot;),//输出路径</span></span><br><span class="line"><span class="string">  &#125;</span></span><br><span class="line"><span class="string">&#125;</span></span><br></pre></td></tr></table></figure>
<hr>
<h3 id="3-mode"><a href="#3-mode" class="headerlink" title="3.mode"></a>3.mode</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  <span class="comment">//开发阶段</span></span><br><span class="line">  <span class="attr">mode</span>: <span class="string">&quot;development&quot;</span></span><br><span class="line">  <span class="comment">//生产阶段</span></span><br><span class="line">  mode： <span class="string">&quot;production&quot;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<hr>
<h3 id="4-loader-amp-plugins"><a href="#4-loader-amp-plugins" class="headerlink" title="4.loader &amp; plugins"></a>4.loader &amp; plugins</h3><h4 id="（1）加载css"><a href="#（1）加载css" class="headerlink" title="（1）加载css"></a>（1）加载css</h4><h5 id="1）解析成style并插入head中"><a href="#1）解析成style并插入head中" class="headerlink" title="1）解析成style并插入head中"></a>1）解析成style并插入head中</h5><ol>
<li>npm i -D css-loader style-loader</li>
<li>在入口文件index.js中import “cssPath”</li>
<li>在index.html中引入输出文件bundle.js</li>
<li>配置module.rules<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  <span class="attr">module</span>: &#123;</span><br><span class="line">    <span class="attr">rules</span>: [</span><br><span class="line">      &#123;</span><br><span class="line">        <span class="attr">test</span>: <span class="regexp">/\.css$/</span>,</span><br><span class="line">        use: [<span class="string">&quot;style-loader&quot;</span>, <span class="string">&quot;css-loader&quot;</span>]</span><br><span class="line">      &#125;</span><br><span class="line">    ]</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
</ol>
<h5 id="2）解析less"><a href="#2）解析less" class="headerlink" title="2）解析less"></a>2）解析less</h5><ol>
<li>npm i -D less</li>
<li>npm i -D less-loader css-loader style-loader </li>
<li>在入口文件index.js中import “lessPath”</li>
<li>在index.html中引入输出文件bundle.js</li>
<li>配置module.rules<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  <span class="attr">module</span>: &#123;</span><br><span class="line">    <span class="attr">rules</span>: [</span><br><span class="line">      &#123;</span><br><span class="line">        <span class="attr">test</span>: <span class="regexp">/\.less$/</span>,</span><br><span class="line">        use: [<span class="string">&quot;style-loader&quot;</span>, <span class="string">&quot;css-loader&quot;</span>, <span class="string">&quot;less-loader&quot;</span>]</span><br><span class="line">      &#125;</span><br><span class="line">    ]</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
</ol>
<h5 id="3）解析cssnext、添加兼容前缀、压缩"><a href="#3）解析cssnext、添加兼容前缀、压缩" class="headerlink" title="3）解析cssnext、添加兼容前缀、压缩"></a>3）解析cssnext、添加兼容前缀、压缩</h5><ol>
<li>npm i -D postcss-loader css-loader style-loader </li>
<li>npm i -D postcss-cssnext autoprefixer cssnano </li>
<li>在入口文件index.js中import “cssPath”</li>
<li>在index.html中引入输出文件bundle.js</li>
<li>配置module.rules<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> MiniCssExtractPlugin = <span class="built_in">require</span>(<span class="string">&quot;mini-css-extract-plugin&quot;</span>);</span><br><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  <span class="attr">module</span>: &#123;</span><br><span class="line">    <span class="attr">rules</span>: [</span><br><span class="line">      &#123;</span><br><span class="line">        <span class="attr">test</span>: <span class="regexp">/\.less$/</span>,</span><br><span class="line">        use: [</span><br><span class="line">          MiniCssExtractPlugin.loader,</span><br><span class="line">          <span class="string">&quot;css-loader&quot;</span>,</span><br><span class="line">          &#123;</span><br><span class="line">            <span class="attr">loader</span>: <span class="string">&quot;postcss-loader&quot;</span>,</span><br><span class="line">            <span class="attr">options</span>:&#123;</span><br><span class="line">              <span class="attr">ident</span>: <span class="string">&quot;postcss&quot;</span>,</span><br><span class="line">              <span class="attr">plugins</span>:[</span><br><span class="line">                <span class="built_in">require</span>(<span class="string">&quot;postcss-cssnext&quot;</span>)(),</span><br><span class="line">                <span class="built_in">require</span>(<span class="string">&quot;autoprefixer&quot;</span>)(),</span><br><span class="line">                <span class="built_in">require</span>(<span class="string">&quot;cssnano&quot;</span>)()</span><br><span class="line">              ]</span><br><span class="line">            &#125;</span><br><span class="line">          &#125;</span><br><span class="line">          <span class="string">&quot;less-loader&quot;</span></span><br><span class="line">        ]</span><br><span class="line">      &#125;</span><br><span class="line">    ]</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">plugins</span>: [</span><br><span class="line">    <span class="keyword">new</span> MiniCssExtractPlugin(&#123;</span><br><span class="line">      <span class="attr">filename</span>: <span class="string">&#x27;[name].css&#x27;</span>,</span><br><span class="line">    &#125;)</span><br><span class="line">  ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
</ol>
<h5 id="4）抽离css成独立文件"><a href="#4）抽离css成独立文件" class="headerlink" title="4）抽离css成独立文件"></a>4）抽离css成独立文件</h5><ol>
<li>npm i -D css-loader style-loader </li>
<li>npm i -D mini-css-extract-plugin </li>
<li>在入口文件index.js中import “cssPath”</li>
<li>在index.html中引入输出文件bundle.js</li>
<li>配置module.rules<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> MiniCssExtractPlugin = <span class="built_in">require</span>(<span class="string">&quot;mini-css-extract-plugin&quot;</span>);</span><br><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  <span class="attr">module</span>: &#123;</span><br><span class="line">    <span class="attr">rules</span>: [</span><br><span class="line">      &#123;</span><br><span class="line">        <span class="attr">test</span>: <span class="regexp">/\.less$/</span>,</span><br><span class="line">        use: [MiniCssExtractPlugin.loader, <span class="string">&quot;css-loader&quot;</span>, <span class="string">&quot;less-loader&quot;</span>]</span><br><span class="line">      &#125;</span><br><span class="line">    ]</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">plugins</span>: [</span><br><span class="line">    <span class="keyword">new</span> MiniCssExtractPlugin(&#123;</span><br><span class="line">      <span class="attr">filename</span>: <span class="string">&#x27;[name].css&#x27;</span>,</span><br><span class="line">    &#125;)</span><br><span class="line">  ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
</ol>
<h5 id="5）free-shaking-css"><a href="#5）free-shaking-css" class="headerlink" title="5）free-shaking css"></a>5）free-shaking css</h5><ol>
<li>npm i -D css-loader</li>
<li>npm i -D purify-css purifycss-webpack glob-all</li>
<li>npm i -D mini-css-extract-plugin </li>
<li>在入口文件index.js中import “cssPath”</li>
<li>在index.html中引入输出文件bundle.js</li>
<li>配置module.rules<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">&quot;path&quot;</span>);</span><br><span class="line"><span class="keyword">const</span> glob = <span class="built_in">require</span>(<span class="string">&quot;glob-all&quot;</span>)</span><br><span class="line"><span class="keyword">const</span> PurifyCssPlugin = <span class="built_in">require</span>(<span class="string">&quot;purifycss-webpack&quot;</span>);</span><br><span class="line"><span class="keyword">const</span> MiniCssExtractPlugin = <span class="built_in">require</span>(<span class="string">&quot;mini-css-extract-plugin&quot;</span>);</span><br><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  <span class="attr">module</span>: &#123;</span><br><span class="line">    <span class="attr">rules</span>: [</span><br><span class="line">      &#123;</span><br><span class="line">        <span class="attr">test</span>: <span class="regexp">/\.less$/</span>,</span><br><span class="line">        use: [MiniCssExtractPlugin.loader, <span class="string">&quot;css-loader&quot;</span>, <span class="string">&quot;less-loader&quot;</span>]</span><br><span class="line">      &#125;</span><br><span class="line">    ]</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">plugins</span>: [</span><br><span class="line">    <span class="keyword">new</span> MiniCssExtractPlugin(&#123;</span><br><span class="line">      <span class="attr">filename</span>: <span class="string">&#x27;[name].css&#x27;</span>,</span><br><span class="line">    &#125;),</span><br><span class="line">    <span class="keyword">new</span> PurifyCssPlugin(&#123;</span><br><span class="line">      <span class="attr">paths</span>: glob.sync([</span><br><span class="line">        path.join(__dirname, <span class="string">&#x27;src/*.html&#x27;</span>),</span><br><span class="line">        path.join(__dirname, <span class="string">&#x27;src/*.js&#x27;</span>),</span><br><span class="line">      ])</span><br><span class="line">    &#125;)</span><br><span class="line">  ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
</ol>
<hr>
<h4 id="（2）加载图片"><a href="#（2）加载图片" class="headerlink" title="（2）加载图片"></a>（2）加载图片</h4><h5 id="1）处理css中背景图片"><a href="#1）处理css中背景图片" class="headerlink" title="1）处理css中背景图片"></a>1）处理css中背景图片</h5><ol>
<li>npm i -D file-loader</li>
<li>在index.html中引入输出文件bundle.js</li>
<li>配置module.rules<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  <span class="attr">mode</span>: <span class="string">&#x27;development&#x27;</span>,</span><br><span class="line"></span><br><span class="line">  <span class="attr">entry</span>: <span class="string">&#x27;./src/index.js&#x27;</span>,</span><br><span class="line"></span><br><span class="line">  <span class="attr">output</span>: &#123;</span><br><span class="line">    <span class="attr">path</span>: path.resolve(__dirname, <span class="string">&#x27;dist&#x27;</span>),</span><br><span class="line">    <span class="attr">filename</span>: <span class="string">&#x27;bundle.js&#x27;</span></span><br><span class="line">  &#125;,</span><br><span class="line"></span><br><span class="line">  <span class="attr">module</span>: &#123;</span><br><span class="line">   <span class="attr">rules</span>: [</span><br><span class="line">      &#123;</span><br><span class="line">        <span class="attr">test</span>: <span class="regexp">/\.(png|jpg|svg|gif)$/</span>,</span><br><span class="line">        use: [</span><br><span class="line">          &#123;</span><br><span class="line">            <span class="attr">loader</span>: <span class="string">&quot;file-loader&quot;</span>,</span><br><span class="line">            <span class="attr">options</span>: &#123;</span><br><span class="line">              <span class="attr">name</span>: <span class="string">&quot;[name].[ext]&quot;</span>,</span><br><span class="line">              <span class="attr">outputPath</span>: <span class="string">&#x27;img&#x27;</span></span><br><span class="line">            &#125;</span><br><span class="line">          &#125;</span><br><span class="line">        ]</span><br><span class="line">      &#125;,</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
</ol>
<h5 id="2）处理html中src图片"><a href="#2）处理html中src图片" class="headerlink" title="2）处理html中src图片"></a>2）处理html中src图片</h5><ol>
<li>npm i -D file-loader url-loader html-loader</li>
<li>npm i -D html-webpack-plugin</li>
<li>在index.html中引入输出文件bundle.js</li>
<li>配置module.rules</li>
<li>配置plugins加载html<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> HtmlWebpackPlugin = <span class="built_in">require</span>(<span class="string">&quot;html-webpack-plugin&quot;</span>);</span><br><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  <span class="attr">module</span>: &#123;</span><br><span class="line">   <span class="attr">rules</span>: [</span><br><span class="line">      &#123;</span><br><span class="line">        <span class="attr">test</span>: <span class="regexp">/\.(png|jpg|svg|gif)$/</span>,</span><br><span class="line">        use: [</span><br><span class="line">          &#123;</span><br><span class="line">            <span class="attr">loader</span>: <span class="string">&quot;url-loader&quot;</span>,</span><br><span class="line">            <span class="attr">options</span>: &#123;</span><br><span class="line">              <span class="attr">name</span>: <span class="string">&quot;[name].[ext]&quot;</span>,</span><br><span class="line">              <span class="attr">limit</span>: <span class="number">100</span>,</span><br><span class="line">              <span class="attr">outputPath</span>: <span class="string">&#x27;img&#x27;</span></span><br><span class="line">            &#125;</span><br><span class="line">          &#125;</span><br><span class="line">        ]</span><br><span class="line">      &#125;,</span><br><span class="line">      &#123;</span><br><span class="line">        <span class="attr">test</span>: <span class="regexp">/\.html$/</span>,</span><br><span class="line">        use: [&#123;</span><br><span class="line">          <span class="attr">loader</span>: <span class="string">&quot;html-loader&quot;</span>,</span><br><span class="line">          <span class="attr">options</span>: &#123;</span><br><span class="line">            <span class="attr">attrs</span>: [<span class="string">&#x27;img:src&#x27;</span>]</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;]</span><br><span class="line">      &#125;,</span><br><span class="line">    ]</span><br><span class="line">  &#125;,</span><br><span class="line"></span><br><span class="line">   <span class="attr">plugins</span>: [</span><br><span class="line">    <span class="keyword">new</span> HtmlWebpackPlugin(&#123;</span><br><span class="line">      <span class="attr">template</span>: <span class="string">&#x27;./src/index.html&#x27;</span></span><br><span class="line">    &#125;)</span><br><span class="line">  ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
</ol>
<h5 id="3）压缩图片"><a href="#3）压缩图片" class="headerlink" title="3）压缩图片"></a>3）压缩图片</h5><ol>
<li>npm i -D file-loader url-loader html-loader img-loader</li>
<li>npm i -D imagemin imagemin-xxx</li>
<li>npm i -D html-webpack-plugin</li>
<li>在index.html中引入输出文件bundle.js</li>
<li>配置module.rules</li>
<li>配置plugins加载html<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> HtmlWebpackPlugin = <span class="built_in">require</span>(<span class="string">&quot;html-webpack-plugin&quot;</span>);</span><br><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  <span class="attr">module</span>: &#123;</span><br><span class="line">   <span class="attr">rules</span>: [</span><br><span class="line">      &#123;</span><br><span class="line">        <span class="attr">test</span>: <span class="regexp">/\.(png|jpg|svg|gif)$/</span>,</span><br><span class="line">        use: [</span><br><span class="line">          &#123;</span><br><span class="line">            <span class="attr">loader</span>: <span class="string">&quot;url-loader&quot;</span>,</span><br><span class="line">            <span class="attr">options</span>: &#123;</span><br><span class="line">              <span class="attr">name</span>: <span class="string">&quot;[name].[ext]&quot;</span>,</span><br><span class="line">              <span class="attr">limit</span>: <span class="number">100</span>,</span><br><span class="line">              <span class="attr">outputPath</span>: <span class="string">&#x27;img&#x27;</span></span><br><span class="line">            &#125;</span><br><span class="line">          &#125;,</span><br><span class="line">          &#123;</span><br><span class="line">            <span class="attr">loader</span>: <span class="string">&quot;img-loader&quot;</span>,</span><br><span class="line">            <span class="attr">options</span>: &#123;</span><br><span class="line">              <span class="attr">plugins</span>: [</span><br><span class="line">                <span class="built_in">require</span>(<span class="string">&quot;imagemin-xxx&quot;</span>)(&#123;</span><br><span class="line">                  <span class="attr">quality</span>: [<span class="number">1</span>,<span class="number">1</span>]</span><br><span class="line">                &#125;)</span><br><span class="line">              ]</span><br><span class="line">            &#125;</span><br><span class="line">          &#125;,</span><br><span class="line">        ]</span><br><span class="line">      &#125;,</span><br><span class="line">      &#123;</span><br><span class="line">        <span class="attr">test</span>: <span class="regexp">/\.html$/</span>,</span><br><span class="line">        use: [&#123;</span><br><span class="line">          <span class="attr">loader</span>: <span class="string">&quot;html-loader&quot;</span>,</span><br><span class="line">          <span class="attr">options</span>: &#123;</span><br><span class="line">            <span class="attr">attrs</span>: [<span class="string">&#x27;img:src&#x27;</span>]</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;]</span><br><span class="line">      &#125;,</span><br><span class="line">    ]</span><br><span class="line">  &#125;,</span><br><span class="line"></span><br><span class="line">   <span class="attr">plugins</span>: [</span><br><span class="line">    <span class="keyword">new</span> HtmlWebpackPlugin(&#123;</span><br><span class="line">      <span class="attr">template</span>: <span class="string">&#x27;./src/index.html&#x27;</span></span><br><span class="line">    &#125;)</span><br><span class="line">  ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
</ol>
<hr>
<h4 id="（3）加载字体"><a href="#（3）加载字体" class="headerlink" title="（3）加载字体"></a>（3）加载字体</h4><ol>
<li>npm i -D file-loader</li>
<li>在index.html中引入输出文件bundle.js</li>
<li>配置module.rules<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">&quot;path&quot;</span>);</span><br><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  <span class="attr">mode</span>: <span class="string">&#x27;development&#x27;</span>,</span><br><span class="line"></span><br><span class="line">  <span class="attr">entry</span>: <span class="string">&#x27;./src/index.js&#x27;</span>,</span><br><span class="line"></span><br><span class="line">  <span class="attr">output</span>: &#123;</span><br><span class="line">    <span class="attr">path</span>: path.resolve(__dirname, <span class="string">&#x27;dist&#x27;</span>),</span><br><span class="line">    <span class="attr">filename</span>: <span class="string">&#x27;bundle.js&#x27;</span></span><br><span class="line">  &#125;,</span><br><span class="line"></span><br><span class="line">  <span class="attr">module</span>: &#123;</span><br><span class="line">   <span class="attr">rules</span>: [</span><br><span class="line">      &#123;</span><br><span class="line">        <span class="attr">test</span>: <span class="regexp">/\.(woff|woff2|eot|ttf|otf)$/</span>,</span><br><span class="line">        use: &#123;</span><br><span class="line">          <span class="attr">loader</span>: <span class="string">&quot;file-loader&quot;</span>,</span><br><span class="line">          <span class="attr">options</span>: &#123;</span><br><span class="line">            <span class="attr">name</span>: <span class="string">&quot;[name].[ext]&quot;</span>,</span><br><span class="line">            <span class="attr">outputPath</span>: <span class="string">&#x27;font&#x27;</span></span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;,</span><br><span class="line">    ]</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
</ol>
<hr>
<h4 id="（4）加载js"><a href="#（4）加载js" class="headerlink" title="（4）加载js"></a>（4）加载js</h4><h5 id="1）js-默认tree-shaking"><a href="#1）js-默认tree-shaking" class="headerlink" title="1）js 默认tree-shaking"></a>1）js 默认tree-shaking</h5><ul>
<li>生产环境下默认自动tree-shaking（基于语法）</li>
</ul>
<h5 id="2）js-深度tree-shaking"><a href="#2）js-深度tree-shaking" class="headerlink" title="2）js 深度tree-shaking"></a>2）js 深度tree-shaking</h5><ol>
<li>npm i -D webpack-deep-scope-plugin</li>
<li>配置 plugins</li>
<li>生产环境下执行深度tree-shaking（基于作用域）<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> webpackDeepScopePlugin = <span class="built_in">require</span>(<span class="string">&quot;webpack-deep-scope-plugin&quot;</span>).default;</span><br><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  <span class="attr">plugins</span>: [</span><br><span class="line">    <span class="keyword">new</span> webpackDeepScopePlugin()</span><br><span class="line">  ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
</ol>
<h5 id="3）lodash工具库"><a href="#3）lodash工具库" class="headerlink" title="3）lodash工具库"></a>3）lodash工具库</h5><ol>
<li>npm i -D lodash-es</li>
<li>import lodash from “lodash-es”<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> lodash <span class="keyword">from</span> <span class="string">&quot;lodash-es&quot;</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">add</span>(<span class="params">a,b</span>)</span>&#123;</span><br><span class="line">  <span class="keyword">return</span> a+b;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">isArray</span>(<span class="params">obj</span>)</span>&#123;</span><br><span class="line">  <span class="built_in">console</span>.log(lodash.isArray(obj))</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> &#123;</span><br><span class="line">  add,</span><br><span class="line">  isArray</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
</ol>
<h5 id="4）提取公共js代码"><a href="#4）提取公共js代码" class="headerlink" title="4）提取公共js代码"></a>4）提取公共js代码</h5><ol>
<li>配置多入口</li>
<li>配置出口</li>
<li>配置 optimization<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  <span class="attr">entry</span>: &#123;</span><br><span class="line">    <span class="attr">index</span>:  <span class="string">&#x27;./src/index.js&#x27;</span>,</span><br><span class="line">    <span class="attr">index2</span>: <span class="string">&#x27;./src/index2.js&#x27;</span>,</span><br><span class="line">  &#125;,</span><br><span class="line"></span><br><span class="line">  <span class="attr">output</span>: &#123;</span><br><span class="line">    <span class="attr">path</span>: path.resolve(__dirname, <span class="string">&#x27;dist&#x27;</span>),</span><br><span class="line">    <span class="attr">filename</span>: <span class="string">&#x27;[name].main.js&#x27;</span>,</span><br><span class="line">    <span class="attr">chunkFilename</span>: <span class="string">&quot;[name].js&quot;</span></span><br><span class="line">  &#125;,</span><br><span class="line"></span><br><span class="line"> <span class="attr">optimization</span>:&#123;</span><br><span class="line">    <span class="attr">splitChunks</span>:&#123;</span><br><span class="line">      <span class="attr">cacheGroups</span>:&#123;</span><br><span class="line">        <span class="comment">//抽离公共代码块</span></span><br><span class="line">        <span class="attr">common</span>:&#123;</span><br><span class="line">          <span class="attr">name</span>:<span class="string">&quot;commonAll&quot;</span>,<span class="comment">//名称</span></span><br><span class="line">          <span class="attr">chunks</span>:<span class="string">&#x27;all&#x27;</span>,<span class="comment">//查找范围</span></span><br><span class="line">          <span class="attr">minSize</span>: <span class="number">1</span>,<span class="comment">//最小体积</span></span><br><span class="line">          <span class="attr">minChunks</span>: <span class="number">2</span>,<span class="comment">//最少次数</span></span><br><span class="line">          <span class="attr">priority</span>: <span class="number">1</span><span class="comment">//优先级</span></span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="comment">//抽离第三方库</span></span><br><span class="line">        <span class="attr">lodash</span>:&#123;</span><br><span class="line">          <span class="attr">name</span>:<span class="string">&quot;lodashAll&quot;</span>,</span><br><span class="line">          <span class="attr">chunks</span>:<span class="string">&#x27;all&#x27;</span>,</span><br><span class="line">          <span class="attr">test</span>: <span class="regexp">/[\\/]node_modules[\\/]/</span>,</span><br><span class="line">          priority: <span class="number">10</span></span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
</ol>
<h5 id="5）解析新ES语法"><a href="#5）解析新ES语法" class="headerlink" title="5）解析新ES语法"></a>5）解析新ES语法</h5><ol>
<li>npm i -D @babel/core @babel/cli @babel/preset-env</li>
<li>配置 module.rules<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> webpackDeepScopePlugin = <span class="built_in">require</span>(<span class="string">&quot;webpack-deep-scope-plugin&quot;</span>).default;</span><br><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  <span class="attr">module</span>: &#123;</span><br><span class="line">    <span class="attr">rules</span>: [</span><br><span class="line">      &#123; <span class="attr">test</span>: <span class="regexp">/\.js$/</span>, exclude: <span class="regexp">/node_modules/</span>, loader: <span class="string">&quot;babel-loader&quot;</span> &#125;</span><br><span class="line">    ]</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
</ol>
<hr>
<h4 id="（5）加载html"><a href="#（5）加载html" class="headerlink" title="（5）加载html"></a>（5）加载html</h4><h5 id="1）生成html"><a href="#1）生成html" class="headerlink" title="1）生成html"></a>1）生成html</h5><ol>
<li>npm i -D html-webpack-plugin</li>
<li>配置 plugin<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> HtmlWebpackPlugin = <span class="built_in">require</span>(<span class="string">&quot;html-webpack-plugin&quot;</span>);</span><br><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  <span class="attr">plugins</span>: [</span><br><span class="line">    <span class="keyword">new</span> HtmlWebpackPlugin(&#123;</span><br><span class="line">      <span class="attr">filename</span>: <span class="string">&#x27;[name].html&#x27;</span>,</span><br><span class="line">      <span class="attr">template</span>: <span class="string">&#x27;src/index.html&#x27;</span>,</span><br><span class="line">      <span class="attr">minify</span>: &#123;</span><br><span class="line">        <span class="attr">removeComments</span>: <span class="literal">true</span>,<span class="comment">//清理注释</span></span><br><span class="line">        <span class="attr">collapseWhitespace</span>: <span class="literal">true</span><span class="comment">//清理空格</span></span><br><span class="line">      &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">  ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
</ol>
<h5 id="2）清理打包文件"><a href="#2）清理打包文件" class="headerlink" title="2）清理打包文件"></a>2）清理打包文件</h5><ol>
<li>npm i -D clean-webpack-plugin</li>
<li>配置 plugin<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> CleanWebpackPlugin = <span class="built_in">require</span>(<span class="string">&quot;clean-webpack-plugin&quot;</span>);</span><br><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  <span class="attr">plugins</span>: [</span><br><span class="line">    <span class="keyword">new</span> CleanWebpackPlugin()</span><br><span class="line">  ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
</ol>
<hr>
<h2 id="（三）package-json-配置"><a href="#（三）package-json-配置" class="headerlink" title="（三）package.json 配置"></a>（三）package.json 配置</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&quot;scripts&quot;</span>:&#123;</span><br><span class="line">  <span class="comment">//npm run 命令</span></span><br><span class="line">  <span class="string">&quot;run&quot;</span>: <span class="string">&quot;webpack --color&quot;</span></span><br><span class="line">  <span class="string">&quot;dev&quot;</span>: <span class="string">&quot;webpack --mode development&quot;</span>,</span><br><span class="line">  <span class="string">&quot;prod&quot;</span>: <span class="string">&quot;webpack --mode production&quot;</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="string">&quot;devDependencies&quot;</span>:&#123;</span><br><span class="line">  <span class="comment">//依赖记录</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

      
      <!-- 打赏 -->
      
    </div>
    <footer class="article-footer">
      <a data-url="https://gitee.com/huafu123/blog/2018/07/11/WEBPACKa/" data-id="ckya9fc17000sygf64c3sf7la"
        class="article-share-link">分享</a>
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/blog/tags/webpack/" rel="tag">webpack</a></li></ul>

    </footer>

  </div>

  

  
  
  

  

</article>
    
  </article>
  

  
  <nav class="page-nav">
    
    <span class="page-number current">1</span><a class="page-number" href="/blog/page/2/">2</a><a class="page-number" href="/blog/page/3/">3</a><a class="extend next" rel="next" href="/blog/page/2/">下一页</a>
  </nav>
  
</section>
</div>

      <footer class="footer">
  <div class="outer">
    <ul class="list-inline">
      <li>
        &copy;
        2020-2022
        Huafu Li
      </li>
      <li>
        
          Powered by
        
        
        <a href="https://hexo.io" target="_blank">Hexo</a> Theme <a href="https://github.com/Shen-Yu/hexo-theme-ayer" target="_blank">Ayer</a>
        
      </li>
    </ul>
    <ul class="list-inline">
      <li>
        
        
        <ul class="list-inline">
  <li>PV:<span id="busuanzi_value_page_pv"></span></li>
  <li>UV:<span id="busuanzi_value_site_uv"></span></li>
</ul>
        
      </li>
      <li>
        <!-- cnzz统计 -->
        
        <script type="text/javascript" src='https://s9.cnzz.com/z_stat.php?id=1278069914&amp;web_id=1278069914'></script>
        
      </li>
    </ul>
  </div>
</footer>
    <div class="to_top">
        <div class="totop" id="totop">
  <i class="ri-arrow-up-line"></i>
</div>
      </div>
    </main>
    
      <aside class="sidebar">
        
        <button class="navbar-toggle"></button>
<nav class="navbar">
  
  <div class="logo">
    <a href="/blog/"><img src="/blog/hu.png" alt="虎虎生辉"></a>
  </div>
  
  <ul class="nav nav-main">
    
    <li class="nav-item">
      <a class="nav-item-link" href="/blog/">主页</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/blog/archives">目录</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/blog/about">关于</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/blog/pictures">相册</a>
    </li>
    
  </ul>
</nav>
<nav class="navbar navbar-bottom">
  <ul class="nav">
    <li class="nav-item">
      
      <a class="nav-item-link nav-item-search"  title="Search">
        <i class="ri-search-line"></i>
      </a>
      
      
      <a class="nav-item-link" target="_blank" href="/blog/atom.xml" title="RSS Feed">
        <i class="ri-rss-line"></i>
      </a>
      
    </li>
  </ul>
</nav>
<div class="search-form-wrap">
  <div class="local-search local-search-plugin">
  <input type="search" id="local-search-input" class="local-search-input" placeholder="Search...">
  <div id="local-search-result" class="local-search-result"></div>
</div>
</div>
      </aside>
      <div id="mask"></div>

<!-- #reward -->
<div id="reward">
  <span class="close"><i class="ri-close-line"></i></span>
  <p class="reward-p"><i class="ri-cup-line"></i>请我喝杯咖啡吧~</p>
  <div class="reward-box">
    
    <div class="reward-item">
      <img class="reward-img" src="/blog/./images/alipay.png">
      <span class="reward-type">支付宝</span>
    </div>
    
    
    <div class="reward-item">
      <img class="reward-img" src="/blog/./images/wechat.png">
      <span class="reward-type">微信</span>
    </div>
    
  </div>
</div>
      
<script src="/blog/js/jquery-2.0.3.min.js"></script>


<script src="/blog/js/jquery.justifiedGallery.min.js"></script>


<script src="/blog/js/lazyload.min.js"></script>


<script src="/blog/js/busuanzi-2.3.pure.min.js"></script>


  
<script src="/blog/fancybox/jquery.fancybox.min.js"></script>





<script>
  var ayerConfig = {
    mathjax: false
  }
</script>


<script src="/blog/js/ayer.js"></script>


<script src="https://cdn.jsdelivr.net/npm/jquery-modal@0.9.2/jquery.modal.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/jquery-modal@0.9.2/jquery.modal.min.css">



<script type="text/javascript" src="https://js.users.51.la/20544303.js"></script>
  
  

  </div>
</body>

</html>